Implement Yandex provider file fetcher

This commit is contained in:
artyom 2018-12-14 19:05:00 +03:00
Родитель ae1b694623
Коммит 9776c1e536
2 изменённых файлов: 111 добавлений и 13 удалений

Просмотреть файл

@ -22,6 +22,7 @@
Margin="0 5">
<StackPanel Margin="10">
<TextBlock Text="{Binding ErrorMessage}"
TextWrapping="Wrap"
Foreground="#990000"/>
</StackPanel>
</StackPanel>

Просмотреть файл

@ -4,28 +4,61 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reactive.Subjects;
using System.Text;
using System.Threading.Tasks;
using Camelotia.Services.Interfaces;
using Camelotia.Services.Models;
using Newtonsoft.Json;
namespace Camelotia.Services.Providers
{
public sealed class YandexFileSystemProvider : IProvider
{
private const string YandexAuthTokenUrl = "https://oauth.yandex.ru/token";
private const string CloudApiGetPathBase = "https://cloud-api.yandex.net:443/v1/disk/resources?path=";
private const string SuccessContent = "<html><body>Please return to the app.</body></html>";
private const string ClientSecret = "f14bfc0275a34ceea83d7de7f4b50898";
private const string ClientId = "122661520b174cb5b85b4a3c26aa66f6";
private readonly ReplaySubject<bool> _isAuthorized = new ReplaySubject<bool>(1);
private string _code;
private string _accessToken;
public string Size => "Unknown";
public string Name => "Yandex Disk";
public string Description => "Yandex Disk file provider";
public Task<IEnumerable<FileModel>> Get(string path) => Task.FromResult(Enumerable.Empty<FileModel>());
public async Task<IEnumerable<FileModel>> Get(string path)
{
using (var http = new HttpClient())
{
http.DefaultRequestHeaders.Accept.Clear();
http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth", _accessToken);
var encodedPath = WebUtility.UrlEncode(path);
var pathUrl = CloudApiGetPathBase + encodedPath;
using (var response = await http.GetAsync(pathUrl).ConfigureAwait(false))
{
var json = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
var content = JsonConvert.DeserializeObject<YandexContentResponse>(json);
var models = content.Embedded.Items
.Select(file => new FileModel(
file.Name,
file.Path.Replace("disk:", ""),
file.Type == "dir",
file.Size));
return models;
}
}
}
public Task DownloadFile(string from, Stream to) => Task.CompletedTask;
@ -41,43 +74,107 @@ namespace Camelotia.Services.Providers
public Task Logout()
{
_code = null;
_accessToken = string.Empty;
_isAuthorized.OnNext(false);
return Task.CompletedTask;
}
public async Task OAuth()
{
var code = await GetAuthenticationCode();
var token = await GetAuthenticationToken(code);
_accessToken = token;
_isAuthorized.OnNext(true);
}
private static async Task<string> GetAuthenticationToken(string code)
{
var form = new Dictionary<string, string>
{
["code"] = code,
["grant_type"] = "authorization_code",
["client_id"] = ClientId,
["client_secret"] = ClientSecret
};
using (var http = new HttpClient())
using (var content = new FormUrlEncodedContent(form))
using (var response = await http.PostAsync(YandexAuthTokenUrl, content).ConfigureAwait(false))
{
var token = await response.Content.ReadAsStringAsync();
var model = JsonConvert.DeserializeObject<YandexTokenAuthResponse>(token);
response.EnsureSuccessStatusCode();
return model.AccessToken;
}
}
private static async Task<string> GetAuthenticationCode()
{
var listener = new HttpListener();
var server = $"http://{IPAddress.Loopback}:{3000}/";
listener.Prefixes.Add(server);
listener.Start();
var process = new Process
{
StartInfo = new ProcessStartInfo
{
UseShellExecute = true,
FileName = GetYandexAuthUrl(server)
FileName = GetYandexAuthCodeUrl(server)
}
};
listener.Start();
process.Start();
var context = await listener.GetContextAsync();
var code = context.Request.QueryString["code"];
_code = code;
var buffer = Encoding.UTF8.GetBytes(SuccessContent);
context.Response.ContentLength64 = buffer.Length;
await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
_isAuthorized.OnNext(true);
context.Response.Close();
listener.Close();
return code;
}
private static string GetYandexAuthUrl(string redirect) =>
"https://oauth.yandex.ru/authorize?response_type=code" +
$"&client_id={ClientId}&redirect_url={redirect}";
private static string GetYandexAuthCodeUrl(string redirect)
{
return "https://oauth.yandex.ru/authorize?response_type=code" +
$"&client_id={ClientId}&redirect_url={redirect}";
}
internal class YandexTokenAuthResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
}
internal class YandexContentResponse
{
[JsonProperty("_embedded")]
public YandexContentItemsResponse Embedded { get; set; }
}
internal class YandexContentItemsResponse
{
[JsonProperty("items")]
public IList<YandexContentItemResponse> Items { get; set; }
}
internal class YandexContentItemResponse
{
[JsonProperty("path")]
public string Path { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("size")]
public string Size { get; set; }
[JsonProperty("created")]
public DateTime Created { get; set; }
}
}
}