Skip to content

Commit

Permalink
Merge branch 'develop2'
Browse files Browse the repository at this point in the history
  • Loading branch information
yar229 committed Nov 3, 2017
2 parents f7e7beb + d28b739 commit 9094fe4
Show file tree
Hide file tree
Showing 41 changed files with 1,217 additions and 594 deletions.
114 changes: 53 additions & 61 deletions MailRuCloud/MailRuCloudApi/Base/Account.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Security.Authentication;
using System.Threading.Tasks;
using YaR.MailRuCloud.Api.Base.Requests;
using YaR.MailRuCloud.Api.Extensions;

namespace YaR.MailRuCloud.Api.Base
{
Expand All @@ -18,8 +19,6 @@ public class Account
/// </summary>
private CookieContainer _cookies;

//private readonly AuthCodeWindow _authCodeHandler = new AuthCodeWindow();

/// <summary>
/// Initializes a new instance of the <see cref="Account" /> class.
/// </summary>
Expand All @@ -39,19 +38,34 @@ public Account(CloudApi cloudApi, string login, string password, ITwoFaHandler t
var twoFaHandler1 = twoFaHandler;
if (twoFaHandler1 != null)
AuthCodeRequiredEvent += twoFaHandler1.Get;

_cachedShards = new Cached<Dictionary<ShardType, ShardInfo>>(() => new ShardInfoRequest(_cloudApi).MakeRequestAsync().Result.ToShardInfo(),
TimeSpan.FromSeconds(ShardsExpiresInSec));

DownloadToken = new Cached<string>(() =>
{
//TODO: not thread safe
var token = new DownloadTokenRequest(_cloudApi).MakeRequestAsync().Result.ToToken();
_cachedShards.Expire();
return token;
},
TimeSpan.FromSeconds(DownloadTokenExpiresSec));

AuthToken = new Cached<string>(() =>
{
//TODO: not thread safe
var token = new AuthTokenRequest(_cloudApi).MakeRequestAsync().Result.ToToken();
DownloadToken.Expire();
return token;
},
TimeSpan.FromSeconds(AuthTokenExpiresInSec));
}

/// <summary>
/// Gets or sets connection proxy.
/// Gets connection proxy.
/// </summary>
/// <value>Proxy settings.</value>
public IWebProxy Proxy { get; set; }

/// <summary>
/// Gets authorization token.
/// </summary>
/// <value>Access token.</value>
public string AuthToken { get; private set; }
public IWebProxy Proxy { get; }

/// <summary>
/// Gets account cookies.
Expand All @@ -63,15 +77,15 @@ public Account(CloudApi cloudApi, string login, string password, ITwoFaHandler t
/// Gets or sets login name.
/// </summary>
/// <value>Account email.</value>
public string LoginName { get; set; }
public string LoginName { get; }

/// <summary>
/// Gets or sets email password.
/// </summary>
/// <value>Password related with login.</value>
public string Password { get; set; }
private string Password { get; }

public AccountInfo Info { get; set; }
public AccountInfo Info { get; private set; }

/// <summary>
/// Authorize on MAIL.RU server.
Expand Down Expand Up @@ -112,55 +126,43 @@ public async Task<bool> LoginAsync()
await new EnsureSdcCookieRequest(_cloudApi)
.MakeRequestAsync();

AuthToken = new AuthTokenRequest(_cloudApi)
.MakeRequestAsync()
.ThrowIf(data => string.IsNullOrEmpty(data.body?.token), new AuthenticationException("Empty auth token"))
.body.token;

Info = new AccountInfo
{
FileSizeLimit = new AccountInfoRequest(_cloudApi).MakeRequestAsync().Result.body.cloud.file_size_limit
};

TokenExpiresAt = DateTime.Now.AddHours(TokenExpiresInSec);
Info = (await new AccountInfoRequest(_cloudApi)
.MakeRequestAsync())
.ToAccountInfo();

return true;
}

public DateTime TokenExpiresAt { get; private set; }
private const int TokenExpiresInSec = 23 * 60 * 60;
/// <summary>
/// Token for authorization
/// </summary>
public readonly Cached<string> AuthToken;
private const int AuthTokenExpiresInSec = 23 * 60 * 60;

/// <summary>
/// Token for downloading files
/// </summary>
public readonly Cached<string> DownloadToken;
private const int DownloadTokenExpiresSec = 20 * 60;

public string DownloadToken
{
get
{
if (string.IsNullOrEmpty(_downloadToken) || (DateTime.Now - _downloadTokenDate).TotalSeconds > DownloadTokenExpiresSec)
{
_downloadTokenDate = DateTime.Now;
var dtres = new DownloadTokenRequest(_cloudApi).MakeRequestAsync().Result;
_downloadToken = dtres.body.token;
}
return _downloadToken;
}
}
private string _downloadToken;
private DateTime _downloadTokenDate = DateTime.MinValue;
private const int DownloadTokenExpiresSec = 2 * 60 * 60;
private readonly Cached<Dictionary<ShardType, ShardInfo>> _cachedShards;
private const int ShardsExpiresInSec = 2 * 60;

/// <summary>
/// Need to add this function for all calls.
/// Get shard info that to do post get request. Can be use for anonymous user.
/// </summary>
internal void CheckAuth()
/// <param name="shardType">Shard type as numeric type.</param>
/// <returns>Shard info.</returns>
public async Task<ShardInfo> GetShardInfo(ShardType shardType)
{
if (LoginName == null || Password == null)
throw new AuthenticationException("Login or password is empty.");

if (string.IsNullOrEmpty(AuthToken))
if (!Login())
throw new AuthenticationException("Auth token has't been retrieved.");
var shards = await Task.Run(() => _cachedShards.Value);
var shard = shards[shardType];
return shard;
}





public delegate string AuthCodeRequiredDelegate(string login, bool isAutoRelogin);

Expand All @@ -170,14 +172,4 @@ protected virtual string OnAuthCodeRequired(string login, bool isAutoRelogin)
return AuthCodeRequiredEvent?.Invoke(login, isAutoRelogin);
}
}

public static class Extensions
{
public static T ThrowIf<T>(this Task<T> data, Func<T, bool> func, Exception ex)
{
var res = data.Result;
if (func(res)) throw ex;
return res;
}
}
}
59 changes: 59 additions & 0 deletions MailRuCloud/MailRuCloudApi/Base/Cached.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;

namespace YaR.MailRuCloud.Api.Base
{
public class Cached<T>
{
private readonly TimeSpan _duration;
private DateTime _expiration;
private Lazy<T> _value;
private readonly Func<T> _valueFactory;

public T Value
{
get
{
RefreshValueIfNeeded();
return _value.Value;
}
}

public Cached(Func<T> valueFactory, TimeSpan duration)
{
_duration = duration;
_valueFactory = valueFactory;

RefreshValueIfNeeded();
}

private readonly object _refreshLock = new object();

private void RefreshValueIfNeeded()
{
if (DateTime.Now >= _expiration)
{
lock (_refreshLock)
{
if (DateTime.Now >= _expiration)
{
_value = new Lazy<T>(_valueFactory);
_expiration = DateTime.Now.Add(_duration);
}
}
}
}

public override string ToString()
{
return Value.ToString();
}

public void Expire()
{
lock (_refreshLock)
{
_expiration = DateTime.MinValue;
}
}
}
}
46 changes: 17 additions & 29 deletions MailRuCloud/MailRuCloudApi/Base/CloudApi.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Security.Authentication;
using System.Threading;
using System.Threading.Tasks;
using YaR.MailRuCloud.Api.Base.Requests;
using YaR.MailRuCloud.Api.Base.Requests.Types;
using YaR.MailRuCloud.Api.Extensions;

namespace YaR.MailRuCloud.Api.Base
Expand All @@ -21,13 +23,7 @@ public class CloudApi : IDisposable
/// Gets or sets account to connect with cloud.
/// </summary>
/// <value>Account info.</value>
public Account Account { get; set; }

//public string DownloadToken { get; set; }




public Account Account { get; }

public CloudApi(string login, string password, ITwoFaHandler twoFaHandler)
{
Expand All @@ -37,23 +33,23 @@ public CloudApi(string login, string password, ITwoFaHandler twoFaHandler)
throw new AuthenticationException("Auth token has't been retrieved.");
}

// !!!!!!!!!!!!!!!! Account.Info = GetAccountInfo().Result;
//_cachedShards = new Cached<Dictionary<ShardType, ShardInfo>>(() => new ShardInfoRequest(this).MakeRequestAsync().Result.ToShardInfo(),
// TimeSpan.FromMinutes(2));
}

///// <summary>
///// Get shard info that to do post get request. Can be use for anonymous user.
///// </summary>
///// <param name="shardType">Shard type as numeric type.</param>
///// <returns>Shard info.</returns>
//public async Task<ShardInfo> GetShardInfo(ShardType shardType)
//{
// var shards = await Task.Run(() => _cachedShards.Value);
// var shard = shards[shardType];
// return shard;
//}

/// <summary>
/// Get shard info that to do post get request. Can be use for anonymous user.
/// </summary>
/// <param name="shardType">Shard type as numeric type.</param>
/// <param name="useAnonymousUser">To get anonymous user.</param>
/// <returns>Shard info.</returns>
public async Task<ShardInfo> GetShardInfo(ShardType shardType, bool useAnonymousUser = false)
{
var data = await new ShardInfoRequest(this, useAnonymousUser).MakeRequestAsync();
var shard = data.ToShardInfo(shardType);
Logger.Info($"Shard: ({shardType}){shard.Url}");
return shard;
}
//private readonly Cached<Dictionary<ShardType, ShardInfo>> _cachedShards;

#region IDisposable Support
private bool _disposedValue;
Expand All @@ -75,13 +71,5 @@ public void Dispose()
Dispose(true);
}
#endregion


}






}
14 changes: 6 additions & 8 deletions MailRuCloud/MailRuCloudApi/Base/DownloadStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace YaR.MailRuCloud.Api.Base
{
public class DownloadStream : Stream
{
private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(typeof(DownloadStream));

private const int InnerBufferSize = 65536;

private readonly IList<File> _files;
Expand All @@ -31,8 +33,8 @@ public DownloadStream(IList<File> files, CloudApi cloud, long? start = null, lon

_cloud = cloud;
_shard = files.All(f => string.IsNullOrEmpty(f.PublicLink))
? _cloud.GetShardInfo(ShardType.Get).Result
: _cloud.GetShardInfo(ShardType.WeblinkGet).Result;
? _cloud.Account.GetShardInfo(ShardType.Get).Result
: _cloud.Account.GetShardInfo(ShardType.WeblinkGet).Result;

_files = files;
_start = start;
Expand Down Expand Up @@ -93,16 +95,12 @@ private async Task<object> GetFileStream()
//TODO: refact
string downloadkey = string.Empty;
if (_shard.Type == ShardType.WeblinkGet)
{
//var dtres = new DownloadTokenHtmlRequest(_cloud, file.PublicLink).MakeRequestAsync().Result;
//downloadkey = dtres.body.token;
downloadkey = _cloud.Account.DownloadToken;
}
downloadkey = _cloud.Account.DownloadToken.Value;
var request = _shard.Type == ShardType.Get
? (HttpWebRequest) WebRequest.Create($"{_shard.Url}{Uri.EscapeDataString(file.FullPath)}")
: (HttpWebRequest)WebRequest.Create($"{_shard.Url}{new Uri(file.PublicLink).PathAndQuery.Remove(0, "/public".Length)}?key={downloadkey}");
Logger.Debug($"HTTP:{request.Method}:{request.RequestUri.AbsoluteUri}");
request.Headers.Add("Accept-Ranges", "bytes");
request.AddRange(instart, inend);
Expand Down
Loading

0 comments on commit 9094fe4

Please sign in to comment.