fix #974 Separate the WebClient and Octokit components that GithubDocumentStore depends on.

pull/976/head
maliming 7 years ago
parent f33e20e2fa
commit e4a1440001

@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="2.2.0" />
<PackageReference Include="Octokit" Version="0.29.0" />
</ItemGroup>

@ -1,4 +1,6 @@
using Volo.Abp.Domain;
using System;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Domain;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@ -35,6 +37,11 @@ namespace Volo.Docs
options.Stores[GithubDocumentStore.Type] = typeof(GithubDocumentStore);
options.Stores[FileSystemDocumentStore.Type] = typeof(FileSystemDocumentStore);
});
context.Services.AddHttpClient(GithubRepositoryManager.HttpClientName, client =>
{
client.Timeout = TimeSpan.FromMilliseconds(15000);
});
}
}
}

@ -1,16 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Octokit;
using Octokit.Internal;
using Volo.Abp.Domain.Services;
using Volo.Docs.Documents;
using Volo.Docs.GitHub.Projects;
using Volo.Docs.Projects;
using Newtonsoft.Json.Linq;
using Octokit;
using ProductHeaderValue = Octokit.ProductHeaderValue;
using Project = Volo.Docs.Projects.Project;
@ -22,6 +20,13 @@ namespace Volo.Docs.GitHub.Documents
{
public const string Type = "GitHub";
private readonly IGithubRepositoryManager _githubRepositoryManager;
public GithubDocumentStore(IGithubRepositoryManager githubRepositoryManager)
{
_githubRepositoryManager = githubRepositoryManager;
}
public virtual async Task<Document> GetDocumentAsync(Project project, string documentName, string version)
{
var token = project.GetGitHubAccessTokenOrNull();
@ -102,20 +107,7 @@ namespace Volo.Docs.GitHub.Documents
var url = project.GetGitHubUrl();
var ownerName = GetOwnerNameFromUrl(url);
var repositoryName = GetRepositoryNameFromUrl(url);
var gitHubClient = CreateGitHubClient(project.GetGitHubAccessTokenOrNull());
return await gitHubClient
.Repository
.Release
.GetAll(ownerName, repositoryName);
}
private static GitHubClient CreateGitHubClient(string token = null)
{
//TODO: Why hard-coded "abpframework"? Should be configurable?
return token.IsNullOrWhiteSpace()
? new GitHubClient(new ProductHeaderValue("abpframework"))
: new GitHubClient(new ProductHeaderValue("abpframework"), new InMemoryCredentialStore(new Credentials(token)));
return await _githubRepositoryManager.GetReleasesAsync(ownerName, repositoryName, project.GetGitHubAccessTokenOrNull());
}
protected virtual string GetOwnerNameFromUrl(string url)
@ -151,19 +143,7 @@ namespace Volo.Docs.GitHub.Documents
{
Logger.LogInformation("Downloading content from Github (DownloadWebContentAsStringAsync): " + rawUrl);
using (var webClient = new GithubWebClient())
{
if (!token.IsNullOrWhiteSpace())
{
webClient.Headers.Add("Authorization", "token " + token);
}
webClient.Headers.Add("User-Agent", userAgent ?? "");
//TODO: SET TIMEOUT?
return await webClient.DownloadStringTaskAsync(new Uri(rawUrl));
}
return await _githubRepositoryManager.GetFileRawStringContentAsync(rawUrl, token, userAgent);
}
catch (Exception ex)
{
@ -179,16 +159,7 @@ namespace Volo.Docs.GitHub.Documents
{
Logger.LogInformation("Downloading content from Github (DownloadWebContentAsByteArrayAsync): " + rawUrl);
using (var webClient = new GithubWebClient())
{
if (!token.IsNullOrWhiteSpace())
{
webClient.Headers.Add("Authorization", "token " + token);
}
webClient.Headers.Add("User-Agent", userAgent ?? "");
return await webClient.DownloadDataTaskAsync(new Uri(rawUrl));
}
return await _githubRepositoryManager.GetFileRawByteArrayContentAsync(rawUrl, token, userAgent);
}
catch (Exception ex)
{
@ -237,21 +208,5 @@ namespace Volo.Docs.GitHub.Documents
.Replace("github.com", "raw.githubusercontent.com")
.ReplaceFirst("/tree/", "/");
}
private class GithubWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var webRequest = base.GetWebRequest(address);
if (webRequest == null)
{
return null;
}
webRequest.Timeout = 15000;
return webRequest;
}
}
}
}

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Octokit;
using Octokit.Internal;
using ProductHeaderValue = Octokit.ProductHeaderValue;
namespace Volo.Docs.GitHub.Documents
{
public class GithubRepositoryManager : IGithubRepositoryManager
{
public const string HttpClientName = "GithubRepositoryManagerHttpClientName";
private readonly IHttpClientFactory _clientFactory;
public GithubRepositoryManager(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<string> GetFileRawStringContentAsync(string rawUrl, string token, string userAgent)
{
var httpClient = _clientFactory.CreateClient(HttpClientName);
if (!token.IsNullOrWhiteSpace())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", token);
}
httpClient.DefaultRequestHeaders.Add("User-Agent", userAgent ?? "");
return await httpClient.GetStringAsync(new Uri(rawUrl));
}
public async Task<byte[]> GetFileRawByteArrayContentAsync(string rawUrl, string token, string userAgent)
{
var httpClient = _clientFactory.CreateClient(HttpClientName);
if (!token.IsNullOrWhiteSpace())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", token);
}
httpClient.DefaultRequestHeaders.Add("User-Agent", userAgent ?? "");
return await httpClient.GetByteArrayAsync(new Uri(rawUrl));
}
public async Task<IReadOnlyList<Release>> GetReleasesAsync(string name, string repositoryName, string token)
{
var client = token.IsNullOrWhiteSpace()
? new GitHubClient(new ProductHeaderValue(name))
: new GitHubClient(new ProductHeaderValue(name), new InMemoryCredentialStore(new Credentials(token)));
return (await client
.Repository
.Release
.GetAll(name, repositoryName)).ToList();
}
}
}

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Octokit;
using Volo.Abp.DependencyInjection;
namespace Volo.Docs.GitHub.Documents
{
public interface IGithubRepositoryManager : ITransientDependency
{
Task<string> GetFileRawStringContentAsync(string rawUrl, string token, string userAgent);
Task<byte[]> GetFileRawByteArrayContentAsync(string rawUrl, string token, string userAgent);
Task<IReadOnlyList<Release>> GetReleasesAsync(string name, string repositoryName, string token);
}
}

@ -1,7 +1,43 @@
namespace Volo.Docs
using System;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;
using Octokit;
using Volo.Docs.GitHub.Documents;
namespace Volo.Docs
{
public abstract class DocsDomainTestBase : DocsTestBase<DocsDomainTestModule>
{
protected override void AfterAddApplication(IServiceCollection services)
{
var repositoryManager = Substitute.For<IGithubRepositoryManager>();
repositoryManager.GetFileRawStringContentAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>())
.Returns("stringContent");
repositoryManager.GetFileRawByteArrayContentAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>())
.Returns(new byte[] { 0x01, 0x02, 0x03 });
repositoryManager.GetReleasesAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>())
.Returns(new List<Release>
{
new Release("https://api.github.com/repos/abpframework/abp/releases/16293679",
"https://github.com/abpframework/abp/releases/tag/0.15.0",
"https://api.github.com/repos/abpframework/abp/releases/16293679/assets",
"https://uploads.github.com/repos/abpframework/abp/releases/16293679/assets{?name,label}",
16293679,
"0.15.0",
"master",
"0.15.0",
"0.15.0 already release",
false,
false,
DateTimeOffset.Parse("2019-03-22T18:43:58Z"),
DateTimeOffset.Parse("2019-03-22T19:44:25Z"),
null,
"https://api.github.com/repos/abpframework/abp/tarball/0.15.0",
"https://api.github.com/repos/abpframework/abp/zipball/0.15.0",
null)
});
services.AddSingleton(repositoryManager);
}
}
}
}

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using NSubstitute;
using Octokit;
using Shouldly;
using Volo.Docs.Documents;
using Volo.Docs.GitHub.Documents;
using Volo.Docs.Projects;
using Xunit;
namespace Volo.Docs
{
public class GithubDocumentStore_Tests : DocsDomainTestBase
{
private readonly IDocumentStoreFactory _documentStoreFactory;
private readonly IProjectRepository _projectRepository;
private readonly DocsTestData _testData;
public GithubDocumentStore_Tests()
{
_documentStoreFactory = GetRequiredService<IDocumentStoreFactory>();
_projectRepository = GetRequiredService<IProjectRepository>();
_testData = GetRequiredService<DocsTestData>();
}
[Fact]
public async Task GetDocumentAsync()
{
var store = _documentStoreFactory.Create(GithubDocumentStore.Type);
var project = await _projectRepository.FindAsync(_testData.PorjectId);
project.ShouldNotBeNull();
var document = await store.GetDocumentAsync(project, "index2", "0.123.0");
document.ShouldNotBeNull();
document.Title.ShouldBe("index2");
document.FileName.ShouldBe("index2");
document.Version.ShouldBe("0.123.0");
document.Content.ShouldBe("stringContent");
}
[Fact]
public async Task GetVersionsAsync()
{
var store = _documentStoreFactory.Create(GithubDocumentStore.Type);
var project = await _projectRepository.FindAsync(_testData.PorjectId);
project.ShouldNotBeNull();
var document = await store.GetVersionsAsync(project);
document.ShouldNotBeNull();
document.Count.ShouldBe(1);
document.ShouldContain(x => x.Name == "0.15.0" && x.DisplayName == "0.15.0");
}
[Fact]
public async Task GetResource()
{
var store = _documentStoreFactory.Create(GithubDocumentStore.Type);
var project = await _projectRepository.FindAsync(_testData.PorjectId);
project.ShouldNotBeNull();
var documentResource = await store.GetResource(project, "index.md", "0.123.0");
documentResource.ShouldNotBeNull();
documentResource.Content.ShouldBe(new byte[]
{
0x01, 0x02, 0x03
});
}
}
}
Loading…
Cancel
Save