Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
b64c34f8bd
40
EPS.SDK/Caching/Cache.cs
Normal file
40
EPS.SDK/Caching/Cache.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using ExtensiblePortfolioSite.SDK.Resources;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ExtensiblePortfolioSite.SDK.Caching
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Global Item Cache
|
||||||
|
/// </summary>
|
||||||
|
public static class Cache
|
||||||
|
{
|
||||||
|
internal static TimeSpan GitUserLifetime = TimeSpan.FromMinutes(1440);
|
||||||
|
internal static TimeSpan GitRepositoryLifetime = TimeSpan.FromMinutes(120);
|
||||||
|
|
||||||
|
private static readonly SortedDictionary<String, GitServiceCache> CacheLookup = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrives the specified <see cref="GitServiceCache"/> for the given provider
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ServiceProvider">Git Service Provider Name</param>
|
||||||
|
/// <returns>Git Service Cache</returns>
|
||||||
|
public static GitServiceCache GetGitServiceCache(String ServiceProvider)
|
||||||
|
{
|
||||||
|
if (CacheLookup.TryGetValue(ServiceProvider, out GitServiceCache? cache))
|
||||||
|
return cache;
|
||||||
|
lock (CacheLookup)
|
||||||
|
{
|
||||||
|
if (CacheLookup.TryGetValue(ServiceProvider, out cache))
|
||||||
|
return cache;
|
||||||
|
|
||||||
|
ServiceProvider = string.Intern(ServiceProvider);
|
||||||
|
|
||||||
|
cache = new GitServiceCache(ServiceProvider);
|
||||||
|
CacheLookup.Add(ServiceProvider, cache);
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
EPS.SDK/Caching/CacheRepo.cs
Normal file
16
EPS.SDK/Caching/CacheRepo.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using ExtensiblePortfolioSite.SDK.Git;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ExtensiblePortfolioSite.SDK.Caching
|
||||||
|
{
|
||||||
|
internal sealed class CacheRepo : GitCacheItemBase<IRepository>
|
||||||
|
{
|
||||||
|
private readonly Uri Repository;
|
||||||
|
|
||||||
|
internal CacheRepo(GitServiceCache Parent, Uri Repository) : base(Parent) => this.Repository = Repository;
|
||||||
|
|
||||||
|
protected override TimeSpan Lifetime => Cache.GitRepositoryLifetime;
|
||||||
|
protected override IRepository RetriveValue() => this.Parent.ServiceProvider.GetRepository(this.Repository);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
EPS.SDK/Caching/CacheUser.cs
Normal file
16
EPS.SDK/Caching/CacheUser.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using ExtensiblePortfolioSite.SDK.Git;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ExtensiblePortfolioSite.SDK.Caching
|
||||||
|
{
|
||||||
|
internal sealed class CacheUser : GitCacheItemBase<IUser>
|
||||||
|
{
|
||||||
|
private readonly Uri User;
|
||||||
|
|
||||||
|
internal CacheUser(GitServiceCache Parent, Uri User) : base(Parent) => this.User = User;
|
||||||
|
|
||||||
|
protected override TimeSpan Lifetime => Cache.GitRepositoryLifetime;
|
||||||
|
protected override IUser RetriveValue() => this.Parent.ServiceProvider.GetUser(this.User);
|
||||||
|
}
|
||||||
|
}
|
||||||
80
EPS.SDK/Caching/GitCacheItemBase.cs
Normal file
80
EPS.SDK/Caching/GitCacheItemBase.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ExtensiblePortfolioSite.SDK.Caching
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base Git Cache Item Class
|
||||||
|
/// </summary>
|
||||||
|
public abstract class GitCacheItemBase : IDisposable, ICacheItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// the <see cref="GitServiceCache"/> this Item is bound to
|
||||||
|
/// </summary>
|
||||||
|
protected readonly GitServiceCache Parent;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="GitCacheItemBase"/>
|
||||||
|
/// <param name="Parent"><see cref="GitServiceCache"/> that this Item is boud to</param>
|
||||||
|
public GitCacheItemBase(GitServiceCache Parent)
|
||||||
|
{
|
||||||
|
this.Parent = Parent;
|
||||||
|
Parent.Register(this);
|
||||||
|
}
|
||||||
|
///
|
||||||
|
~GitCacheItemBase() => this.Disposing();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ICacheItem.Invalidate"/>
|
||||||
|
public abstract void Invalidate();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IDisposable.Dispose"/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
this.Disposing();
|
||||||
|
}
|
||||||
|
private void Disposing() => this.Parent.Unregister(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base Git Cache Item Class
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Cache </typeparam>
|
||||||
|
public abstract class GitCacheItemBase<T> : GitCacheItemBase, ICacheItem<T>
|
||||||
|
{
|
||||||
|
private T CacheValue;
|
||||||
|
private DateTime RetrivedTime;
|
||||||
|
|
||||||
|
internal GitCacheItemBase(GitServiceCache Parent) : base(Parent)
|
||||||
|
{
|
||||||
|
this.RetrivedTime = DateTime.MinValue;
|
||||||
|
this.CacheValue = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="GitCacheItemBase.Invalidate"/>
|
||||||
|
public override void Invalidate()
|
||||||
|
{
|
||||||
|
this.CacheValue = default!;
|
||||||
|
this.RetrivedTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
/// <inheritdoc cref="ICacheItem{T}.GetValue"/>
|
||||||
|
public T GetValue()
|
||||||
|
{
|
||||||
|
if (DateTime.Now - this.RetrivedTime > this.Lifetime)
|
||||||
|
{
|
||||||
|
this.CacheValue = RetriveValue();
|
||||||
|
this.RetrivedTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
return this.CacheValue!;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Expected Cache Item Lifetime
|
||||||
|
/// </summary>
|
||||||
|
protected abstract TimeSpan Lifetime { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// Retrive the Cache Item
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Cache Item</returns>
|
||||||
|
protected abstract T RetriveValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
107
EPS.SDK/Caching/GitServiceCache.cs
Normal file
107
EPS.SDK/Caching/GitServiceCache.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using ExtensiblePortfolioSite.SDK.Git;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ExtensiblePortfolioSite.SDK.Caching
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Git Service Cache Provider
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GitServiceCache : IGitCacheProvider, IDisposable
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="IGitCacheProvider.ServiceProvider"/>
|
||||||
|
public GitService ServiceProvider { get; }
|
||||||
|
private readonly LinkedList<GitCacheItemBase> CacheItems = new();
|
||||||
|
private Boolean _disposing = false;
|
||||||
|
|
||||||
|
internal GitServiceCache(String Provider) : this(GitManager.GetService(Provider)) { }
|
||||||
|
internal GitServiceCache(GitService ServiceProvider)
|
||||||
|
{
|
||||||
|
this.ServiceProvider = ServiceProvider;
|
||||||
|
this.ServiceProvider.OnChange += ServiceProvider_OnChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ServiceProvider_OnChange(GitService Git)
|
||||||
|
{
|
||||||
|
lock(this.CacheItems)
|
||||||
|
{
|
||||||
|
foreach (GitCacheItemBase Item in this.CacheItems)
|
||||||
|
Item.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private readonly SortedDictionary<String, GitCacheItemBase<IUser>> UserCaches = new();
|
||||||
|
private readonly SortedDictionary<String, GitCacheItemBase<IRepository>> RepositoryCaches = new();
|
||||||
|
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IGitCacheProvider.GetUser(Uri)"/>
|
||||||
|
public GitCacheItemBase<IUser> GetUser(Uri UserProfile)
|
||||||
|
{
|
||||||
|
String url = UserProfile.ToString();
|
||||||
|
if (UserCaches.TryGetValue(url, out GitCacheItemBase<IUser>? cache))
|
||||||
|
return cache;
|
||||||
|
|
||||||
|
lock (UserCaches)
|
||||||
|
{
|
||||||
|
if (UserCaches.TryGetValue(url, out cache))
|
||||||
|
return cache;
|
||||||
|
|
||||||
|
cache = new CacheUser(this, UserProfile);
|
||||||
|
UserCaches.Add(url, cache);
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <inheritdoc cref="IGitCacheProvider.GetRepository(Uri)"/>
|
||||||
|
public GitCacheItemBase<IRepository> GetRepository(Uri RepositoryURL)
|
||||||
|
{
|
||||||
|
String url = RepositoryURL.ToString();
|
||||||
|
if (RepositoryCaches.TryGetValue(url, out GitCacheItemBase<IRepository>? cache))
|
||||||
|
return cache;
|
||||||
|
|
||||||
|
lock (RepositoryCaches)
|
||||||
|
{
|
||||||
|
if (RepositoryCaches.TryGetValue(url, out cache))
|
||||||
|
return cache;
|
||||||
|
|
||||||
|
cache = new CacheRepo(this, RepositoryURL);
|
||||||
|
RepositoryCaches.Add(url, cache);
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ICacheProvider{GitCacheItemBase}.Register(GitCacheItemBase)"/>
|
||||||
|
public void Register(GitCacheItemBase CacheItem)
|
||||||
|
{
|
||||||
|
if (!_disposing)
|
||||||
|
lock (CacheItems)
|
||||||
|
{
|
||||||
|
this.CacheItems.AddFirst(CacheItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <inheritdoc cref="ICacheProvider{GitCacheItemBase}.Unregister(GitCacheItemBase)"/>
|
||||||
|
public void Unregister(GitCacheItemBase CacheItem)
|
||||||
|
{
|
||||||
|
if (!_disposing)
|
||||||
|
lock (CacheItems)
|
||||||
|
if (this.CacheItems.Remove(CacheItem)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IDisposable"/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_disposing = true;
|
||||||
|
lock (CacheItems)
|
||||||
|
{
|
||||||
|
this.ServiceProvider.OnChange -= ServiceProvider_OnChange;
|
||||||
|
this.RepositoryCaches.Clear();
|
||||||
|
this.UserCaches.Clear();
|
||||||
|
foreach (GitCacheItemBase Item in CacheItems)
|
||||||
|
Item.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
EPS.SDK/Caching/interfaces.cs
Normal file
79
EPS.SDK/Caching/interfaces.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using ExtensiblePortfolioSite.SDK.Git;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ExtensiblePortfolioSite.SDK.Caching
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Cache Item Provider
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TCacheItemType">Cache Item Base Type</typeparam>
|
||||||
|
public interface ICacheProvider<TCacheItemType> where TCacheItemType : ICacheItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a Cache Item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Item"></param>
|
||||||
|
void Register(TCacheItemType Item);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unregisters a Cache Item
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Item"></param>
|
||||||
|
void Unregister(TCacheItemType Item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Cache Item
|
||||||
|
/// </summary>
|
||||||
|
public interface ICacheItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invalidates the Cache Item
|
||||||
|
/// </summary>
|
||||||
|
void Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Cache Item of Type <typeparamref name="T"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Cache Item Type</typeparam>
|
||||||
|
public interface ICacheItem<T> : ICacheItem
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Requested Cache Item
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
T GetValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Git Cache Invalidate or Changed Delegate Callback
|
||||||
|
/// </summary>
|
||||||
|
public delegate void GitCacheInvalidateDelegate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A Git Cache Provider
|
||||||
|
/// </summary>
|
||||||
|
public interface IGitCacheProvider : ICacheProvider<GitCacheItemBase>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Service Provider tied to this Cache
|
||||||
|
/// </summary>
|
||||||
|
public GitService ServiceProvider { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a User by its URL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="UserProfile">User Profile URL</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public GitCacheItemBase<IUser> GetUser(Uri UserProfile);
|
||||||
|
/// <summary>
|
||||||
|
/// Get a Repositroy by its URL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="RepositoryURL">Repository URL</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public GitCacheItemBase<IRepository> GetRepository(Uri RepositoryURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
using System;
|
using ExtensiblePortfolioSite.SDK.Plugins;
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace ExtensiblePortfolioSite.SDK.Git
|
namespace ExtensiblePortfolioSite.SDK.Git
|
||||||
@ -7,34 +9,6 @@ namespace ExtensiblePortfolioSite.SDK.Git
|
|||||||
{
|
{
|
||||||
private static readonly SortedDictionary<String, GitService> Providers = new();
|
private static readonly SortedDictionary<String, GitService> Providers = new();
|
||||||
|
|
||||||
public static void Register(String Service, IGitProvider Provider)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Registering service {Service}");
|
|
||||||
if (Providers.TryGetValue(Service, out GitService? GitService))
|
|
||||||
{
|
|
||||||
GitService.addProvider(Provider);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lock (Providers)
|
|
||||||
{
|
|
||||||
if (Providers.TryGetValue(Service, out GitService))
|
|
||||||
{
|
|
||||||
GitService.addProvider(Provider);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GitService = new GitService(Service);
|
|
||||||
GitService.addProvider(Provider);
|
|
||||||
Providers.Add(Service, GitService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Unregister(String Service, IGitProvider Provider)
|
|
||||||
{
|
|
||||||
if (Providers.TryGetValue(Service, out GitService? GitService))
|
|
||||||
GitService.removeProvider(Provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GitService GetService(String Website) => Providers[Website];
|
public static GitService GetService(String Website) => Providers[Website];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,54 +1,99 @@
|
|||||||
using System;
|
using ExtensiblePortfolioSite.SDK.Caching;
|
||||||
|
using ExtensiblePortfolioSite.SDK.Plugins;
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ExtensiblePortfolioSite.SDK.Git
|
namespace ExtensiblePortfolioSite.SDK.Git
|
||||||
{
|
{
|
||||||
internal class GitService
|
/// <summary>
|
||||||
|
/// Git Service Changed Delegate/Callback
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Git">Sender</param>
|
||||||
|
public delegate void GitServiceChangedDelegate(GitService Git);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Git Service
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GitService
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Git Service Name
|
||||||
|
/// </summary>
|
||||||
public String Service { get; }
|
public String Service { get; }
|
||||||
|
|
||||||
public GitService(String Service)
|
/// <summary>
|
||||||
|
/// OnChanged Event Callback
|
||||||
|
/// </summary>
|
||||||
|
public event GitServiceChangedDelegate? OnChange;
|
||||||
|
|
||||||
|
internal GitService(String Service) => this.Service = Service;
|
||||||
|
|
||||||
|
private readonly SortedDictionary<String, IGitProvider> Providers = new();
|
||||||
|
|
||||||
|
internal void I_RemoveProvider(Plugin FromPlugin, IGitProvider provider)
|
||||||
{
|
{
|
||||||
this.Service = Service;
|
lock (this.Providers)
|
||||||
|
this.Providers.Add(FromPlugin.Info.Name, provider);
|
||||||
|
|
||||||
|
OnChange?.Invoke(this);
|
||||||
|
}
|
||||||
|
internal void I_AddProvider(Plugin FromPlugin, IGitProvider provider)
|
||||||
|
{
|
||||||
|
lock (this.Providers)
|
||||||
|
this.Providers.Add(FromPlugin.Info.Name, provider);
|
||||||
|
|
||||||
|
OnChange?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<IGitProvider> Providers = new();
|
private GitServiceCache? ServiceCache;
|
||||||
|
|
||||||
internal void removeProvider(IGitProvider provider)
|
/// <summary>
|
||||||
|
/// Gets the Service Cache
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public GitServiceCache GetCache() => this.ServiceCache ??= Cache.GetGitServiceCache(this.Service);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempt to Retrive a GitProvider by its PluginName
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="PluginName"></param>
|
||||||
|
/// <param name="Provider"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public void TryGetProviderByPlugin(String PluginName, out IGitProvider? Provider) => this.Providers.TryGetValue(PluginName, out Provider);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrives a Specified User by URL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="URL"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="GitObjectNotFoundException"></exception>
|
||||||
|
public IUser GetUser(Uri URL)
|
||||||
{
|
{
|
||||||
lock (this.Providers)
|
lock (this.Providers)
|
||||||
this.Providers.Remove(provider);
|
foreach (IGitProvider Provider in this.Providers.Values)
|
||||||
}
|
if (Provider.TryGetUserByURL(URL, out IUser? User))
|
||||||
internal void addProvider(IGitProvider provider)
|
|
||||||
{
|
|
||||||
lock (this.Providers)
|
|
||||||
this.Providers.Add(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IUser GetUser(Uri Path)
|
|
||||||
{
|
|
||||||
lock (this.Providers)
|
|
||||||
{
|
|
||||||
foreach(IGitProvider Provider in this.Providers)
|
|
||||||
if (Provider.TryGetUserByURL(Path, out IUser? User))
|
|
||||||
return User!;
|
return User!;
|
||||||
|
|
||||||
throw new GitObjectNotFoundException(GitReferenceKind.User, Path);
|
throw new GitObjectNotFoundException(GitReferenceKind.User, URL);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public IRepository GetRepository(Uri Path)
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrives a Specified Repository by URL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="URL"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="GitObjectNotFoundException"></exception>
|
||||||
|
public IRepository GetRepository(Uri URL)
|
||||||
{
|
{
|
||||||
lock (this.Providers)
|
lock (this.Providers)
|
||||||
{
|
foreach (IGitProvider Provider in this.Providers.Values)
|
||||||
foreach (IGitProvider Provider in this.Providers)
|
if (Provider.TryGetRepositoryByURL(URL, out IRepository? Repository))
|
||||||
if (Provider.TryGetRepositoryByURL(Path, out IRepository? Repository))
|
|
||||||
return Repository!;
|
return Repository!;
|
||||||
|
|
||||||
throw new GitObjectNotFoundException(GitReferenceKind.User, Path);
|
throw new GitObjectNotFoundException(GitReferenceKind.Repository, URL);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace ExtensiblePortfolioSite.SDK.Git
|
namespace ExtensiblePortfolioSite.SDK.Git
|
||||||
{
|
{
|
||||||
@ -30,19 +26,19 @@ namespace ExtensiblePortfolioSite.SDK.Git
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to Get a User Profile by its Website URL
|
/// Attempts to Get a User Profile by its Website URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Boolean TryGetRepositoryByURL(Uri UserProfile, out IRepository? Repository);
|
public Boolean TryGetRepositoryByURL(Uri URL, out IRepository? Repository);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a User Profile by its Website URL
|
/// Get a User Profile by its Website URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IUser GetUserByURL(Uri UserProfile) =>
|
public IUser GetUserByURL(Uri URL) =>
|
||||||
TryGetUserByURL(UserProfile, out IUser? user)
|
TryGetUserByURL(URL, out IUser? user)
|
||||||
? user!
|
? user!
|
||||||
: throw new GitObjectNotFoundException(GitReferenceKind.User, UserProfile);
|
: throw new GitObjectNotFoundException(GitReferenceKind.User, URL);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to Get a User Profile by its Website URL
|
/// Attempts to Get a User Profile by its Website URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Boolean TryGetUserByURL(Uri UserProfile, out IUser? User);
|
public Boolean TryGetUserByURL(Uri URL, out IUser? User);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ using System.Text.Json.Serialization;
|
|||||||
|
|
||||||
namespace ExtensiblePortfolioSite.SDK.Plugins
|
namespace ExtensiblePortfolioSite.SDK.Plugins
|
||||||
{
|
{
|
||||||
|
internal delegate void PluginUnloadDelegate(Plugin plugin);
|
||||||
internal class Plugin : IPluginManagedLibrary
|
internal class Plugin : IPluginManagedLibrary
|
||||||
{
|
{
|
||||||
private class PluginLoadContext : AssemblyLoadContext
|
private class PluginLoadContext : AssemblyLoadContext
|
||||||
@ -42,6 +43,8 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
|||||||
public Assembly Assembly { get; private set; }
|
public Assembly Assembly { get; private set; }
|
||||||
public EPSPluginAttribute Info { get; private set; }
|
public EPSPluginAttribute Info { get; private set; }
|
||||||
|
|
||||||
|
public event PluginUnloadDelegate? OnUnloading;
|
||||||
|
|
||||||
public IList<IPluginLibrary> Dependents { get; } = new List<IPluginLibrary>();
|
public IList<IPluginLibrary> Dependents { get; } = new List<IPluginLibrary>();
|
||||||
IReadOnlyList<IPluginLibrary> IPluginLibrary.References => References.AsReadOnly();
|
IReadOnlyList<IPluginLibrary> IPluginLibrary.References => References.AsReadOnly();
|
||||||
public List<IPluginLibrary> References = new();
|
public List<IPluginLibrary> References = new();
|
||||||
@ -58,8 +61,8 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<JsonConverter> JsonConverters = new();
|
private readonly List<JsonConverter> JsonConverters = new();
|
||||||
private readonly List<KeyValuePair<Type, String[]>> ResourceContainers = new();
|
private readonly Dictionary<Type, String[]> ResourceContainers = new();
|
||||||
private readonly List<KeyValuePair<String, IGitProvider>> GitProviders = new();
|
private readonly Dictionary<GitService, IGitProvider> GitProviders = new();
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
if (Initialized)
|
if (Initialized)
|
||||||
@ -76,8 +79,9 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
|||||||
if (t.IsAssignableTo(typeof(IGitProvider)) && t.GetConstructor(Type.EmptyTypes) != null)
|
if (t.IsAssignableTo(typeof(IGitProvider)) && t.GetConstructor(Type.EmptyTypes) != null)
|
||||||
if (Activator.CreateInstance(t, true) is IGitProvider Provider)
|
if (Activator.CreateInstance(t, true) is IGitProvider Provider)
|
||||||
{
|
{
|
||||||
GitManager.Register(GitProviderAttr.ServiceName, Provider);
|
GitService Service = GitManager.GetService(GitProviderAttr.ServiceName);
|
||||||
GitProviders.Add(new(GitProviderAttr.ServiceName, Provider));
|
GitProviders.Add(Service, Provider);
|
||||||
|
Service.I_AddProvider(this, Provider);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
PluginManager.LogMessage(PluginErrorSeverity.Error, this, "Failed to Instantiate GitProvider", t, null);
|
PluginManager.LogMessage(PluginErrorSeverity.Error, this, "Failed to Instantiate GitProvider", t, null);
|
||||||
@ -105,13 +109,14 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
ResourceContainers.Add(t, ResourceContainerAttr.Schemes);
|
||||||
ResourceManager.Register(t, ResourceContainerAttr.Schemes);
|
ResourceManager.Register(t, ResourceContainerAttr.Schemes);
|
||||||
ResourceContainers.Add(new(t, ResourceContainerAttr.Schemes));
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
PluginManager.LogMessage(PluginErrorSeverity.Fatal, this, "Faield to Create ResoruceContainer Factory", t, ex);
|
PluginManager.LogMessage(PluginErrorSeverity.Fatal, this, "Failed to Create ResoruceContainer Factory", t, ex);
|
||||||
throw new Exception("Runtime Unstable!", ex);
|
Console.Error.WriteLine("Runtime Unstable, Exitting!");
|
||||||
|
Environment.Exit(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -122,8 +127,10 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
|||||||
|
|
||||||
public void Disposing()
|
public void Disposing()
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<String, IGitProvider> provider in GitProviders)
|
OnUnloading?.Invoke(this);
|
||||||
GitManager.Unregister(provider.Key, provider.Value);
|
|
||||||
|
foreach (KeyValuePair<GitService, IGitProvider> provider in GitProviders)
|
||||||
|
provider.Key.I_RemoveProvider(this, provider.Value);
|
||||||
this.GitProviders.Clear();
|
this.GitProviders.Clear();
|
||||||
|
|
||||||
foreach (KeyValuePair<Type, String[]> resourceContainer in ResourceContainers)
|
foreach (KeyValuePair<Type, String[]> resourceContainer in ResourceContainers)
|
||||||
|
|||||||
@ -55,9 +55,7 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
|||||||
Directory.CreateDirectory(RootPath);
|
Directory.CreateDirectory(RootPath);
|
||||||
LibraryPaths.Add(RootPath);
|
LibraryPaths.Add(RootPath);
|
||||||
foreach (String Dll in Directory.EnumerateFiles(RootPath, "*.dll", SearchOption.TopDirectoryOnly))
|
foreach (String Dll in Directory.EnumerateFiles(RootPath, "*.dll", SearchOption.TopDirectoryOnly))
|
||||||
{
|
|
||||||
TryLoadPlugin(Path.GetFullPath(Dll, RootPath), out Plugin? _);
|
TryLoadPlugin(Path.GetFullPath(Dll, RootPath), out Plugin? _);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public static Boolean TryLoadPlugin(string AsmPath, out Plugin? plugin)
|
public static Boolean TryLoadPlugin(string AsmPath, out Plugin? plugin)
|
||||||
{
|
{
|
||||||
@ -380,5 +378,15 @@ namespace ExtensiblePortfolioSite.SDK.Plugins
|
|||||||
// we want to throw when its trying to load something we don't explicitly allow!
|
// we want to throw when its trying to load something we don't explicitly allow!
|
||||||
throw new FileNotFoundException($"Unable to Load Assembly '{Name}'");
|
throw new FileNotFoundException($"Unable to Load Assembly '{Name}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static Plugin? ResolveTypeToPlugin(Type type)
|
||||||
|
{
|
||||||
|
String fname = type.Assembly.GetName().FullName;
|
||||||
|
lock (_plugins)
|
||||||
|
foreach (Plugin plugin in _plugins)
|
||||||
|
if (plugin.Assembly.GetName().FullName == fname)
|
||||||
|
return plugin;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
using ExtensiblePortfolioSite.SDK;
|
using ExtensiblePortfolioSite.SDK;
|
||||||
|
using ExtensiblePortfolioSite.SDK.Caching;
|
||||||
|
using ExtensiblePortfolioSite.SDK.Git;
|
||||||
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace ExtensiblePortfolioSite
|
namespace ExtensiblePortfolioSite
|
||||||
@ -111,6 +112,8 @@ namespace ExtensiblePortfolioSite
|
|||||||
if (Repository == null) throw new Exception("GitRepo Repository missing!");
|
if (Repository == null) throw new Exception("GitRepo Repository missing!");
|
||||||
if (Description == null) throw new Exception("GitRepo Description missing!");
|
if (Description == null) throw new Exception("GitRepo Description missing!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IRepository Resolve() => GitManager.GetService(this.ServiceProvider).GetRepository(this.Repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@ -138,10 +141,6 @@ namespace ExtensiblePortfolioSite
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class Cache
|
public class Cache
|
||||||
{
|
{
|
||||||
[JsonPropertyName("GitCommit")]
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
|
||||||
public Int32 GitCommit = 30;
|
|
||||||
|
|
||||||
[JsonPropertyName("GitRepo")]
|
[JsonPropertyName("GitRepo")]
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
public Int32 GitRepo = 120;
|
public Int32 GitRepo = 120;
|
||||||
@ -196,6 +195,10 @@ namespace ExtensiblePortfolioSite
|
|||||||
Conf = Json.Deserialize<ConfigObject>(File.ReadAllText(ConfigFile));
|
Conf = Json.Deserialize<ConfigObject>(File.ReadAllText(ConfigFile));
|
||||||
if (Conf == null)
|
if (Conf == null)
|
||||||
throw new Exception("Failed to Load Config!");
|
throw new Exception("Failed to Load Config!");
|
||||||
|
|
||||||
|
// Load Config
|
||||||
|
Cache.GitUserLifetime = TimeSpan.FromMinutes(Conf.CacheSection.GitUser);
|
||||||
|
Cache.GitRepositoryLifetime = TimeSpan.FromMinutes(Conf.CacheSection.GitRepo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,8 +27,12 @@
|
|||||||
<None Include="Pages\Projects\Index.cshtml" />
|
<None Include="Pages\Projects\Index.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Folder Include="logs\" />
|
||||||
|
<Folder Include="Plugins\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
<Target Name="IncludePlugins" BeforeTargets="AfterBuild">
|
<Target Name="IncludePlugins" BeforeTargets="AfterBuild">
|
||||||
<MSBuild Projects="..\GithubPlugin\GithubPlugin.csproj" BuildInParallel="$(BuildInParallel)" Targets="Build">
|
<MSBuild Projects="..\GithubPlugin\GithubPlugin.csproj" BuildInParallel="$(BuildInParallel)" Targets="Rebuild">
|
||||||
</MSBuild>
|
</MSBuild>
|
||||||
<Copy SourceFiles="$(SolutionDir)GithubPlugin\bin\$(Configuration)\net6.0\GithubPlugin.dll" DestinationFolder="Plugins/" SkipUnchangedFiles="true" />
|
<Copy SourceFiles="$(SolutionDir)GithubPlugin\bin\$(Configuration)\net6.0\GithubPlugin.dll" DestinationFolder="Plugins/" SkipUnchangedFiles="true" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|||||||
@ -25,14 +25,14 @@ namespace ExtensiblePortfolioSite
|
|||||||
{
|
{
|
||||||
this.Parent = Parent;
|
this.Parent = Parent;
|
||||||
this.Identifier = Identifier;
|
this.Identifier = Identifier;
|
||||||
this.Parent.ScopeStack.AddLast(this);
|
lock (this.Parent.ScopeStack)
|
||||||
|
this.Parent.ScopeStack.AddLast(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
// we shouldn't need this but we evidently do...
|
lock (this.Parent.ScopeStack)
|
||||||
// some form of race condition is causing a null ref Exception
|
this.Parent.ScopeStack.Remove(this);
|
||||||
try { this.Parent.ScopeStack.Remove(this); } catch { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
|
|||||||
|
|
||||||
namespace ExtensiblePortfolioSite.Pages.About
|
namespace ExtensiblePortfolioSite.Pages.About
|
||||||
{
|
{
|
||||||
|
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any, NoStore = false)]
|
||||||
public class AboutModel : PageModel
|
public class AboutModel : PageModel
|
||||||
{
|
{
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
namespace ExtensiblePortfolioSite.Pages
|
namespace ExtensiblePortfolioSite.Pages
|
||||||
{
|
{
|
||||||
|
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any, NoStore = false)]
|
||||||
public class IndexModel : PageModel
|
public class IndexModel : PageModel
|
||||||
{
|
{
|
||||||
private readonly ILogger<IndexModel> _logger;
|
private readonly ILogger<IndexModel> _logger;
|
||||||
@ -13,7 +15,7 @@ namespace ExtensiblePortfolioSite.Pages
|
|||||||
|
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
namespace ExtensiblePortfolioSite.Pages
|
namespace ExtensiblePortfolioSite.Pages
|
||||||
{
|
{
|
||||||
|
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any, NoStore = false)]
|
||||||
public class ProjectsModel : PageModel
|
public class ProjectsModel : PageModel
|
||||||
{
|
{
|
||||||
private readonly ILogger<IndexModel> _logger;
|
private readonly ILogger<IndexModel> _logger;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
|
|||||||
|
|
||||||
namespace ExtensiblePortfolioSite.Pages.Socials
|
namespace ExtensiblePortfolioSite.Pages.Socials
|
||||||
{
|
{
|
||||||
|
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Any, NoStore = false)]
|
||||||
public class SocialsModel : PageModel
|
public class SocialsModel : PageModel
|
||||||
{
|
{
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
|
|||||||
@ -93,12 +93,14 @@ namespace ExtensiblePortfolioSite
|
|||||||
// TODO: [Plugin] Web Static Files Provider
|
// TODO: [Plugin] Web Static Files Provider
|
||||||
// TODO: [Plugin] Web Hook Provider
|
// TODO: [Plugin] Web Hook Provider
|
||||||
// TODO: [Plugin] API Endpoint Provider
|
// TODO: [Plugin] API Endpoint Provider
|
||||||
// TODO: [Plugin] Standard Cache Provider
|
|
||||||
// TODO: [Plugin] Reloading/Updating/Disabling
|
// TODO: [Plugin] Reloading/Updating/Disabling
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
|
|
||||||
|
// Add Responce Cache
|
||||||
|
builder.Services.AddResponseCaching();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
@ -115,6 +117,8 @@ namespace ExtensiblePortfolioSite
|
|||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseResponseCaching();
|
||||||
|
|
||||||
//app.UseAuthorization(); // not needed
|
//app.UseAuthorization(); // not needed
|
||||||
|
|
||||||
app.MapRazorPages();
|
app.MapRazorPages();
|
||||||
|
|||||||
@ -7,6 +7,13 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
},
|
},
|
||||||
"applicationUrl": "https://localhost:58428;http://localhost:58429"
|
"applicationUrl": "https://localhost:58428;http://localhost:58429"
|
||||||
|
},
|
||||||
|
"Docker": {
|
||||||
|
"commandName": "Docker",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
||||||
|
"publishAllPorts": true,
|
||||||
|
"useSSL": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +78,6 @@
|
|||||||
// Caching Options
|
// Caching Options
|
||||||
"Cache": {
|
"Cache": {
|
||||||
// Lifetimes given in minutes (0 = disabled)
|
// Lifetimes given in minutes (0 = disabled)
|
||||||
"GitCommit": 30, //30m
|
|
||||||
"GitRepo": 120, //2h
|
"GitRepo": 120, //2h
|
||||||
"GitUser": 1440 //1d
|
"GitUser": 1440 //1d
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,5 +147,6 @@ namespace GithubPlugin
|
|||||||
{
|
{
|
||||||
return httpClient.GetAsync(resourceLocation).Result;
|
return httpClient.GetAsync(resourceLocation).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user