Merge branch 'feature/backend-refactor' into feature/asc-federatedlogin-refactor

This commit is contained in:
Maksim Chegulov 2022-02-14 17:54:26 +03:00
commit aa102f9435
162 changed files with 7964 additions and 8010 deletions

2
.gitignore vendored
View File

@ -10,7 +10,7 @@
/build/deploy
*.log
/products/ASC.People/Data/
Data/
/Data
Logs/
**/.DS_Store
.eslintcache

View File

@ -4,184 +4,184 @@ namespace ASC.Api.Core;
public abstract class BaseStartup
{
public IConfiguration Configuration { get; }
public IHostEnvironment HostEnvironment { get; }
public virtual JsonConverter[] Converters { get; }
public virtual bool AddControllersAsServices { get; } = false;
public virtual bool ConfirmAddScheme { get; } = false;
public virtual bool AddAndUseSession { get; } = false;
protected DIHelper DIHelper { get; }
protected bool LoadProducts { get; set; } = true;
protected bool LoadConsumers { get; } = true;
public IConfiguration Configuration { get; }
public IHostEnvironment HostEnvironment { get; }
public virtual JsonConverter[] Converters { get; }
public virtual bool AddControllersAsServices { get; } = false;
public virtual bool ConfirmAddScheme { get; } = false;
public virtual bool AddAndUseSession { get; } = false;
protected DIHelper DIHelper { get; }
protected bool LoadProducts { get; set; } = true;
protected bool LoadConsumers { get; } = true;
public BaseStartup(IConfiguration configuration, IHostEnvironment hostEnvironment)
{
Configuration = configuration;
HostEnvironment = hostEnvironment;
DIHelper = new DIHelper();
public BaseStartup(IConfiguration configuration, IHostEnvironment hostEnvironment)
{
Configuration = configuration;
HostEnvironment = hostEnvironment;
DIHelper = new DIHelper();
if (bool.TryParse(Configuration["core:products"], out var loadProducts))
{
LoadProducts = loadProducts;
if (bool.TryParse(Configuration["core:products"], out var loadProducts))
{
LoadProducts = loadProducts;
}
}
}
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddCustomHealthCheck(Configuration);
services.AddHttpContextAccessor();
services.AddMemoryCache();
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddCustomHealthCheck(Configuration);
services.AddHttpContextAccessor();
services.AddMemoryCache();
services.AddHttpClient();
if (AddAndUseSession)
if (AddAndUseSession)
{
services.AddSession();
services.AddSession();
}
DIHelper.Configure(services);
DIHelper.Configure(services);
Action<JsonOptions> jsonOptions = options =>
{
options.JsonSerializerOptions.WriteIndented = false;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.Converters.Add(new ApiDateTimeConverter());
if (Converters != null)
{
foreach (var c in Converters)
Action<JsonOptions> jsonOptions = options =>
{
options.JsonSerializerOptions.Converters.Add(c);
}
options.JsonSerializerOptions.WriteIndented = false;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.Converters.Add(new ApiDateTimeConverter());
if (Converters != null)
{
foreach (var c in Converters)
{
options.JsonSerializerOptions.Converters.Add(c);
}
}
};
services.AddControllers()
.AddXmlSerializerFormatters()
.AddJsonOptions(jsonOptions);
services.AddSingleton(jsonOptions);
DIHelper.TryAdd<DisposeMiddleware>();
DIHelper.TryAdd<CultureMiddleware>();
DIHelper.TryAdd<IpSecurityFilter>();
DIHelper.TryAdd<PaymentFilter>();
DIHelper.TryAdd<ProductSecurityFilter>();
DIHelper.TryAdd<TenantStatusFilter>();
DIHelper.TryAdd<ConfirmAuthHandler>();
DIHelper.TryAdd<CookieAuthHandler>();
DIHelper.TryAdd<WebhooksGlobalFilterAttribute>();
var redisConfiguration = Configuration.GetSection("Redis").Get<RedisConfiguration>();
var kafkaConfiguration = Configuration.GetSection("kafka").Get<KafkaSettings>();
if (kafkaConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCacheNotify<>));
}
};
else if (redisConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(RedisCacheNotify<>));
services.AddControllers()
.AddXmlSerializerFormatters()
.AddJsonOptions(jsonOptions);
services.AddStackExchangeRedisExtensions<NewtonsoftSerializer>(redisConfiguration);
}
else
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(MemoryCacheNotify<>));
}
services.AddSingleton(jsonOptions);
DIHelper.TryAdd(typeof(IWebhookPublisher), typeof(WebhookPublisher));
DIHelper.TryAdd<DisposeMiddleware>();
DIHelper.TryAdd<CultureMiddleware>();
DIHelper.TryAdd<IpSecurityFilter>();
DIHelper.TryAdd<PaymentFilter>();
DIHelper.TryAdd<ProductSecurityFilter>();
DIHelper.TryAdd<TenantStatusFilter>();
DIHelper.TryAdd<ConfirmAuthHandler>();
DIHelper.TryAdd<CookieAuthHandler>();
DIHelper.TryAdd<WebhooksGlobalFilterAttribute>();
var redisConfiguration = Configuration.GetSection("Redis").Get<RedisConfiguration>();
var kafkaConfiguration = Configuration.GetSection("kafka").Get<KafkaSettings>();
if (kafkaConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCache<>));
}
else if (redisConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(RedisCache<>));
services.AddStackExchangeRedisExtensions<NewtonsoftSerializer>(redisConfiguration);
}
else
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(MemoryCacheNotify<>));
}
DIHelper.TryAdd(typeof(IWebhookPublisher), typeof(WebhookPublisher));
if (LoadProducts)
{
DIHelper.RegisterProducts(Configuration, HostEnvironment.ContentRootPath);
}
if (LoadProducts)
{
DIHelper.RegisterProducts(Configuration, HostEnvironment.ContentRootPath);
}
services.AddMvcCore(config =>
{
config.Conventions.Add(new ControllerNameAttributeConvention());
{
config.Conventions.Add(new ControllerNameAttributeConvention());
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
config.Filters.Add(new AuthorizeFilter(policy));
config.Filters.Add(new TypeFilterAttribute(typeof(TenantStatusFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(PaymentFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(IpSecurityFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(ProductSecurityFilter)));
config.Filters.Add(new CustomResponseFilterAttribute());
config.Filters.Add(new CustomExceptionFilterAttribute());
config.Filters.Add(new TypeFilterAttribute(typeof(FormatFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(WebhooksGlobalFilterAttribute)));
config.Filters.Add(new AuthorizeFilter(policy));
config.Filters.Add(new TypeFilterAttribute(typeof(TenantStatusFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(PaymentFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(IpSecurityFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(ProductSecurityFilter)));
config.Filters.Add(new CustomResponseFilterAttribute());
config.Filters.Add(new CustomExceptionFilterAttribute());
config.Filters.Add(new TypeFilterAttribute(typeof(FormatFilter)));
config.Filters.Add(new TypeFilterAttribute(typeof(WebhooksGlobalFilterAttribute)));
config.OutputFormatters.RemoveType<XmlSerializerOutputFormatter>();
config.OutputFormatters.Add(new XmlOutputFormatter());
});
config.OutputFormatters.RemoveType<XmlSerializerOutputFormatter>();
config.OutputFormatters.Add(new XmlOutputFormatter());
});
var authBuilder = services.AddAuthentication("cookie")
.AddScheme<AuthenticationSchemeOptions, CookieAuthHandler>("cookie", a => { });
var authBuilder = services.AddAuthentication("cookie")
.AddScheme<AuthenticationSchemeOptions, CookieAuthHandler>("cookie", a => { });
if (ConfirmAddScheme)
{
authBuilder.AddScheme<AuthenticationSchemeOptions, ConfirmAuthHandler>("confirm", a => { });
if (ConfirmAddScheme)
{
authBuilder.AddScheme<AuthenticationSchemeOptions, ConfirmAuthHandler>("confirm", a => { });
}
services.AddAutoMapper(Assembly.GetAssembly(typeof(MappingProfile)));
}
services.AddAutoMapper(Assembly.GetAssembly(typeof(MappingProfile)));
}
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseRouting();
app.UseRouting();
if (AddAndUseSession)
if (AddAndUseSession)
{
app.UseSession();
app.UseSession();
}
app.UseAuthentication();
app.UseAuthentication();
app.UseAuthorization();
app.UseAuthorization();
app.UseCultureMiddleware();
app.UseCultureMiddleware();
app.UseDisposeMiddleware();
app.UseDisposeMiddleware();
app.UseEndpoints(endpoints =>
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapCustom();
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
}
public void ConfigureContainer(ContainerBuilder builder)
{
endpoints.MapControllers();
endpoints.MapCustom();
endpoints.MapHealthChecks("/health", new HealthCheckOptions()
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
endpoints.MapHealthChecks("/liveness", new HealthCheckOptions
{
Predicate = r => r.Name.Contains("self")
});
});
}
public void ConfigureContainer(ContainerBuilder builder)
{
builder.Register(Configuration, LoadProducts, LoadConsumers);
}
builder.Register(Configuration, LoadProducts, LoadConsumers);
}
}
public static class LogNLogConfigureExtenstion
{
public static IHostBuilder ConfigureNLogLogging(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureLogging((hostBuildexContext, r) =>
public static IHostBuilder ConfigureNLogLogging(this IHostBuilder hostBuilder)
{
return hostBuilder.ConfigureLogging((hostBuildexContext, r) =>
{
_ = new ConfigureLogNLog(hostBuildexContext.Configuration,
new ConfigurationExtension(hostBuildexContext.Configuration), hostBuildexContext.HostingEnvironment);
r.AddNLog(LogManager.Configuration);
});
}
r.AddNLog(LogManager.Configuration);
});
}
}

View File

@ -18,7 +18,7 @@ global using System.Threading;
global using System.Threading.Tasks;
global using System.Web;
global using System.Xml.Linq;
global using StackExchange.Redis.Extensions.Newtonsoft;
global using ASC.Api.Core;
global using ASC.Api.Core.Auth;
global using ASC.Api.Core.Convention;
@ -80,4 +80,5 @@ global using Newtonsoft.Json.Serialization;
global using NLog;
global using NLog.Extensions.Logging;
global using StackExchange.Redis.Extensions.Core.Configuration;
global using StackExchange.Redis.Extensions.Core.Configuration;
global using StackExchange.Redis.Extensions.Newtonsoft;

View File

@ -24,9 +24,6 @@
<EmbeddedResource Include="Utils\TimeZoneConverter\windowsZones.xml" />
<EmbeddedResource Include="Utils\TimeZoneConverter\timeZoneNames.xml" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Notify\AWSEmail.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ARSoft.Tools.NetStandard.DXSdata" Version="1.0.0" />
<PackageReference Include="Autofac.Configuration" Version="6.0.0" />
@ -64,7 +61,4 @@
<Protobuf Include="protos\distributed_task_cache.proto" />
<Protobuf Include="protos\distributed_task_cancelation.proto" />
</ItemGroup>
<ItemGroup>
<Folder Include="Notify\" />
</ItemGroup>
</Project>

View File

@ -23,129 +23,125 @@
*
*/
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Singletone]
public class AscCacheNotify
{
[Singletone]
public class AscCacheNotify
private readonly ICacheNotify<AscCacheItem> _cacheNotify;
public AscCacheNotify(ICacheNotify<AscCacheItem> cacheNotify)
{
private ICacheNotify<AscCacheItem> CacheNotify { get; }
_cacheNotify = cacheNotify;
public AscCacheNotify(ICacheNotify<AscCacheItem> cacheNotify)
{
CacheNotify = cacheNotify;
CacheNotify.Subscribe((item) => { OnClearCache(); }, CacheNotifyAction.Any);
}
_cacheNotify.Subscribe((item) => { OnClearCache(); }, CacheNotifyAction.Any);
}
public void ClearCache()
{
CacheNotify.Publish(new AscCacheItem { Id = Guid.NewGuid().ToString() }, CacheNotifyAction.Any);
}
public void ClearCache() => _cacheNotify.Publish(new AscCacheItem { Id = Guid.NewGuid().ToString() }, CacheNotifyAction.Any);
public static void OnClearCache()
{
public static void OnClearCache()
{
var keys = MemoryCache.Default.Select(r => r.Key);
foreach (var k in keys)
{
MemoryCache.Default.Remove(k);
}
foreach (var k in keys)
{
MemoryCache.Default.Remove(k);
}
}
}
[Singletone]
public class AscCache : ICache
{
private readonly IMemoryCache _memoryCache;
private readonly ConcurrentDictionary<string, object> _memoryCacheKeys;
public AscCache(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
_memoryCacheKeys = new ConcurrentDictionary<string, object>();
}
public T Get<T>(string key) where T : class
{
return _memoryCache.Get<T>(key);
}
public void Insert(string key, object value, TimeSpan sligingExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetSlidingExpiration(sligingExpiration)
.RegisterPostEvictionCallback(EvictionCallback);
_memoryCache.Set(key, value, options);
_memoryCacheKeys.TryAdd(key, null);
}
public void Insert(string key, object value, DateTime absolutExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(absolutExpiration == DateTime.MaxValue ? DateTimeOffset.MaxValue : new DateTimeOffset(absolutExpiration))
.RegisterPostEvictionCallback(EvictionCallback);
_memoryCache.Set(key, value, options);
_memoryCacheKeys.TryAdd(key, null);
}
public void Remove(string key)
{
_memoryCache.Remove(key);
}
public void Remove(Regex pattern)
{
var copy = _memoryCacheKeys.ToDictionary(p => p.Key, p => p.Value);
var keys = copy.Select(p => p.Key).Where(k => pattern.IsMatch(k));
foreach (var key in keys)
{
_memoryCache.Remove(key);
}
}
[Singletone]
public class AscCache : ICache
{
private IMemoryCache MemoryCache { get; }
private ConcurrentDictionary<string, object> MemoryCacheKeys { get; }
public ConcurrentDictionary<string, T> HashGetAll<T>(string key) =>
_memoryCache.GetOrCreate(key, r => new ConcurrentDictionary<string, T>());
public AscCache(IMemoryCache memoryCache)
public T HashGet<T>(string key, string field)
{
if (_memoryCache.TryGetValue<ConcurrentDictionary<string, T>>(key, out var dic)
&& dic.TryGetValue(field, out var value))
{
MemoryCache = memoryCache;
MemoryCacheKeys = new ConcurrentDictionary<string, object>();
}
public T Get<T>(string key) where T : class
{
return MemoryCache.Get<T>(key);
}
public void Insert(string key, object value, TimeSpan sligingExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetSlidingExpiration(sligingExpiration)
.RegisterPostEvictionCallback(EvictionCallback);
MemoryCache.Set(key, value, options);
MemoryCacheKeys.TryAdd(key, null);
}
public void Insert(string key, object value, DateTime absolutExpiration)
{
var options = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(absolutExpiration == DateTime.MaxValue ? DateTimeOffset.MaxValue : new DateTimeOffset(absolutExpiration))
.RegisterPostEvictionCallback(EvictionCallback);
MemoryCache.Set(key, value, options);
MemoryCacheKeys.TryAdd(key, null);
return value;
}
private void EvictionCallback(object key, object value, EvictionReason reason, object state)
return default;
}
public void HashSet<T>(string key, string field, T value)
{
var dic = HashGetAll<T>(key);
if (value != null)
{
MemoryCacheKeys.TryRemove(key.ToString(), out _);
dic.AddOrUpdate(field, value, (k, v) => value);
_memoryCache.Set(key, dic, DateTime.MaxValue);
}
public void Remove(string key)
{
MemoryCache.Remove(key);
}
public void Remove(Regex pattern)
{
var copy = MemoryCacheKeys.ToDictionary(p => p.Key, p => p.Value);
var keys = copy.Select(p => p.Key).Where(k => pattern.IsMatch(k));
foreach (var key in keys)
{
MemoryCache.Remove(key);
}
}
public ConcurrentDictionary<string, T> HashGetAll<T>(string key)
{
return MemoryCache.GetOrCreate(key, r => new ConcurrentDictionary<string, T>());
}
public T HashGet<T>(string key, string field)
{
if (MemoryCache.TryGetValue<ConcurrentDictionary<string, T>>(key, out var dic) && dic.TryGetValue(field, out var value))
{
return value;
}
return default;
}
public void HashSet<T>(string key, string field, T value)
{
var dic = HashGetAll<T>(key);
if (value != null)
else if (dic != null)
{
dic.TryRemove(field, out _);
if (dic.IsEmpty)
{
dic.AddOrUpdate(field, value, (k, v) => value);
MemoryCache.Set(key, dic, DateTime.MaxValue);
}
else if (dic != null)
{
dic.TryRemove(field, out _);
if (dic.Count == 0)
{
MemoryCache.Remove(key);
}
else
{
MemoryCache.Set(key, dic, DateTime.MaxValue);
}
}
}
}
_memoryCache.Remove(key);
}
else
{
_memoryCache.Set(key, dic, DateTime.MaxValue);
}
}
}
private void EvictionCallback(object key, object value, EvictionReason reason, object state)
{
_memoryCacheKeys.TryRemove(key.ToString(), out _);
}
}

View File

@ -23,15 +23,14 @@
*
*/
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Flags]
public enum CacheNotifyAction
{
[Flags]
public enum CacheNotifyAction
{
Insert = 1,
Update = 2,
Remove = 4,
InsertOrUpdate = Insert | Update,
Any = InsertOrUpdate | Remove,
}
}
Insert = 1,
Update = 2,
Remove = 4,
InsertOrUpdate = Insert | Update,
Any = InsertOrUpdate | Remove,
}

View File

@ -23,26 +23,24 @@
*
*/
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Singletone(typeof(AscCache))]
public interface ICache
{
[Singletone(typeof(AscCache))]
public interface ICache
{
T Get<T>(string key) where T : class;
void Insert(string key, object value, TimeSpan sligingExpiration);
void Insert(string key, object value, DateTime absolutExpiration);
void Remove(string key);
void Remove(Regex pattern);
ConcurrentDictionary<string, T> HashGetAll<T>(string key);
T HashGet<T>(string key, string field);
void HashSet<T>(string key, string field, T value);
}
}
T Get<T>(string key) where T : class;
void Insert(string key, object value, TimeSpan sligingExpiration);
void Insert(string key, object value, DateTime absolutExpiration);
void Remove(string key);
void Remove(Regex pattern);
ConcurrentDictionary<string, T> HashGetAll<T>(string key);
T HashGet<T>(string key, string field);
void HashSet<T>(string key, string field, T value);
}

View File

@ -23,15 +23,14 @@
*
*/
namespace ASC.Common.Caching
{
[Singletone]
public interface ICacheNotify<T> where T : IMessage<T>, new()
{
void Publish(T obj, CacheNotifyAction action);
namespace ASC.Common.Caching;
void Subscribe(Action<T> onchange, CacheNotifyAction action);
void Unsubscribe(CacheNotifyAction action);
}
}
[Singletone]
public interface ICacheNotify<T> where T : IMessage<T>, new()
{
void Publish(T obj, CacheNotifyAction action);
void Subscribe(Action<T> onchange, CacheNotifyAction action);
void Unsubscribe(CacheNotifyAction action);
}

View File

@ -1,199 +0,0 @@
namespace ASC.Common.Caching
{
[Singletone]
public class KafkaCache<T> : IDisposable, ICacheNotify<T> where T : IMessage<T>, new()
{
private ClientConfig ClientConfig { get; set; }
private AdminClientConfig AdminClientConfig { get; set; }
private ILog Log { get; set; }
private ConcurrentDictionary<string, CancellationTokenSource> Cts { get; set; }
private ConcurrentDictionary<string, Action<T>> Actions { get; set; }
private ProtobufSerializer<T> ValueSerializer { get; } = new ProtobufSerializer<T>();
private ProtobufDeserializer<T> ValueDeserializer { get; } = new ProtobufDeserializer<T>();
private ProtobufSerializer<AscCacheItem> KeySerializer { get; } = new ProtobufSerializer<AscCacheItem>();
private ProtobufDeserializer<AscCacheItem> KeyDeserializer { get; } = new ProtobufDeserializer<AscCacheItem>();
private IProducer<AscCacheItem, T> Producer { get; set; }
private Guid Key { get; set; }
public KafkaCache(ConfigurationExtension configuration, IOptionsMonitor<ILog> options)
{
Log = options.CurrentValue;
Cts = new ConcurrentDictionary<string, CancellationTokenSource>();
Actions = new ConcurrentDictionary<string, Action<T>>();
Key = Guid.NewGuid();
var settings = configuration.GetSetting<KafkaSettings>("kafka");
ClientConfig = new ClientConfig { BootstrapServers = settings.BootstrapServers };
AdminClientConfig = new AdminClientConfig { BootstrapServers = settings.BootstrapServers };
}
public void Publish(T obj, CacheNotifyAction cacheNotifyAction)
{
try
{
if (Producer == null)
{
Producer = new ProducerBuilder<AscCacheItem, T>(new ProducerConfig(ClientConfig))
.SetErrorHandler((_, e) => Log.Error(e))
.SetKeySerializer(KeySerializer)
.SetValueSerializer(ValueSerializer)
.Build();
}
var channelName = GetChannelName(cacheNotifyAction);
if (Actions.TryGetValue(channelName, out var onchange))
{
onchange(obj);
}
var message = new Message<AscCacheItem, T>
{
Value = obj,
Key = new AscCacheItem
{
Id = Key.ToString()
}
};
Producer.ProduceAsync(channelName, message);
}
catch (ProduceException<Null, string> e)
{
Log.Error(e);
}
catch (Exception e)
{
Log.Error(e);
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction cacheNotifyAction)
{
var channelName = GetChannelName(cacheNotifyAction);
Cts[channelName] = new CancellationTokenSource();
Actions[channelName] = onchange;
void action()
{
var conf = new ConsumerConfig(ClientConfig)
{
GroupId = Guid.NewGuid().ToString()
};
using (var adminClient = new AdminClientBuilder(AdminClientConfig)
.SetErrorHandler((_, e) => Log.Error(e))
.Build())
{
try
{
//TODO: must add checking exist
adminClient.CreateTopicsAsync(
new TopicSpecification[]
{
new TopicSpecification
{
Name = channelName,
NumPartitions = 1,
ReplicationFactor = 1
}
}).Wait();
}
catch (AggregateException)
{
}
}
using var c = new ConsumerBuilder<AscCacheItem, T>(conf)
.SetErrorHandler((_, e) => Log.Error(e))
.SetKeyDeserializer(KeyDeserializer)
.SetValueDeserializer(ValueDeserializer)
.Build();
c.Assign(new TopicPartition(channelName, new Partition()));
try
{
while (true)
{
try
{
var cr = c.Consume(Cts[channelName].Token);
if (cr != null && cr.Message != null && cr.Message.Value != null && !(new Guid(cr.Message.Key.Id)).Equals(Key) && Actions.TryGetValue(channelName, out var act))
{
try
{
act(cr.Message.Value);
}
catch (Exception e)
{
Log.Error("Kafka onmessage", e);
}
}
}
catch (ConsumeException e)
{
Log.Error(e);
}
}
}
catch (OperationCanceledException)
{
c.Close();
}
}
var task = new Task(action, TaskCreationOptions.LongRunning);
task.Start();
}
private string GetChannelName(CacheNotifyAction cacheNotifyAction)
{
return $"ascchannel{cacheNotifyAction}{typeof(T).FullName}".ToLower();
}
public void Unsubscribe(CacheNotifyAction action)
{
Cts.TryGetValue(GetChannelName(action), out var source);
if (source != null)
{
source.Cancel();
}
}
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing && Producer != null)
{
Producer.Dispose();
}
disposedValue = true;
}
}
~KafkaCache()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public class KafkaSettings
{
public string BootstrapServers { get; set; }
}
}

View File

@ -0,0 +1,196 @@
namespace ASC.Common.Caching;
[Singletone]
public class KafkaCacheNotify<T> : IDisposable, ICacheNotify<T> where T : IMessage<T>, new()
{
private IProducer<AscCacheItem, T> _producer;
private bool _disposedValue = false; // To detect redundant calls
private readonly ClientConfig _clientConfig;
private readonly AdminClientConfig _adminClientConfig;
private readonly ILog _logger;
private readonly ConcurrentDictionary<string, CancellationTokenSource> _cancelationToken;
private readonly ConcurrentDictionary<string, Action<T>> _actions;
private readonly ProtobufSerializer<T> _valueSerializer = new ProtobufSerializer<T>();
private readonly ProtobufDeserializer<T> _valueDeserializer = new ProtobufDeserializer<T>();
private readonly ProtobufSerializer<AscCacheItem> _keySerializer = new ProtobufSerializer<AscCacheItem>();
private readonly ProtobufDeserializer<AscCacheItem> _keyDeserializer = new ProtobufDeserializer<AscCacheItem>();
private readonly Guid _key;
public KafkaCacheNotify(ConfigurationExtension configuration, IOptionsMonitor<ILog> options)
{
_logger = options.CurrentValue;
_cancelationToken = new ConcurrentDictionary<string, CancellationTokenSource>();
_actions = new ConcurrentDictionary<string, Action<T>>();
_key = Guid.NewGuid();
var settings = configuration.GetSetting<KafkaSettings>("kafka");
_clientConfig = new ClientConfig { BootstrapServers = settings.BootstrapServers };
_adminClientConfig = new AdminClientConfig { BootstrapServers = settings.BootstrapServers };
}
public void Publish(T obj, CacheNotifyAction notifyAction)
{
try
{
if (_producer == null)
{
_producer = new ProducerBuilder<AscCacheItem, T>(new ProducerConfig(_clientConfig))
.SetErrorHandler((_, e) => _logger.Error(e))
.SetKeySerializer(_keySerializer)
.SetValueSerializer(_valueSerializer)
.Build();
}
var channelName = GetChannelName(notifyAction);
if (_actions.TryGetValue(channelName, out var onchange))
{
onchange(obj);
}
var message = new Message<AscCacheItem, T>
{
Value = obj,
Key = new AscCacheItem
{
Id = _key.ToString()
}
};
_producer.ProduceAsync(channelName, message);
}
catch (ProduceException<Null, string> e)
{
_logger.Error(e);
}
catch (Exception e)
{
_logger.Error(e);
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction notifyAction)
{
var channelName = GetChannelName(notifyAction);
_cancelationToken[channelName] = new CancellationTokenSource();
_actions[channelName] = onchange;
void action()
{
var conf = new ConsumerConfig(_clientConfig)
{
GroupId = Guid.NewGuid().ToString()
};
using (var adminClient = new AdminClientBuilder(_adminClientConfig)
.SetErrorHandler((_, e) => _logger.Error(e))
.Build())
{
try
{
//TODO: must add checking exist
adminClient.CreateTopicsAsync(
new TopicSpecification[]
{
new TopicSpecification
{
Name = channelName,
NumPartitions = 1,
ReplicationFactor = 1
}
}).Wait();
}
catch (AggregateException) { }
}
using var c = new ConsumerBuilder<AscCacheItem, T>(conf)
.SetErrorHandler((_, e) => _logger.Error(e))
.SetKeyDeserializer(_keyDeserializer)
.SetValueDeserializer(_valueDeserializer)
.Build();
c.Assign(new TopicPartition(channelName, new Partition()));
try
{
while (true)
{
try
{
var cr = c.Consume(_cancelationToken[channelName].Token);
if (cr != null && cr.Message != null && cr.Message.Value != null && !(new Guid(cr.Message.Key.Id)).Equals(_key) && _actions.TryGetValue(channelName, out var act))
{
try
{
act(cr.Message.Value);
}
catch (Exception e)
{
_logger.Error("Kafka onmessage", e);
}
}
}
catch (ConsumeException e)
{
_logger.Error(e);
}
}
}
catch (OperationCanceledException)
{
c.Close();
}
}
var task = new Task(action, TaskCreationOptions.LongRunning);
task.Start();
}
public void Unsubscribe(CacheNotifyAction notifyAction)
{
_cancelationToken.TryGetValue(GetChannelName(notifyAction), out var source);
if (source != null)
{
source.Cancel();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing && _producer != null)
{
_producer.Dispose();
}
_disposedValue = true;
}
}
~KafkaCacheNotify()
{
Dispose(false);
}
private string GetChannelName(CacheNotifyAction notifyAction)
{
return $"ascchannel{notifyAction}{typeof(T).FullName}".ToLower();
}
}
public class KafkaSettings
{
public string BootstrapServers { get; set; }
}

View File

@ -1,40 +1,39 @@
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
[Singletone]
public class MemoryCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
{
[Singletone]
public class MemoryCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
private readonly ConcurrentDictionary<string, List<Action<T>>> _actions;
public MemoryCacheNotify()
{
private readonly ConcurrentDictionary<string, List<Action<T>>> _actions;
_actions = new ConcurrentDictionary<string, List<Action<T>>>();
}
public MemoryCacheNotify()
public void Publish(T obj, CacheNotifyAction notifyAction)
{
if (_actions.TryGetValue(GetKey(notifyAction), out var onchange) && onchange != null)
{
_actions = new ConcurrentDictionary<string, List<Action<T>>>();
}
public void Publish(T obj, CacheNotifyAction action)
{
if (_actions.TryGetValue(GetKey(action), out var onchange) && onchange != null)
{
Parallel.ForEach(onchange, a => a(obj));
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction notifyAction)
{
if (onchange != null)
{
_actions.GetOrAdd(GetKey(notifyAction), new List<Action<T>>())
.Add(onchange);
}
}
public void Unsubscribe(CacheNotifyAction action)
{
_actions.TryRemove(GetKey(action), out _);
}
private string GetKey(CacheNotifyAction cacheNotifyAction)
{
return $"asc:channel:{cacheNotifyAction}:{typeof(T).FullName}".ToLower();
Parallel.ForEach(onchange, a => a(obj));
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction notifyAction)
{
if (onchange != null)
{
_actions.GetOrAdd(GetKey(notifyAction), new List<Action<T>>())
.Add(onchange);
}
}
public void Unsubscribe(CacheNotifyAction notifyAction)
{
_actions.TryRemove(GetKey(notifyAction), out _);
}
private string GetKey(CacheNotifyAction notifyAction)
{
return $"asc:channel:{notifyAction}:{typeof(T).FullName}".ToLower();
}
}

View File

@ -1,37 +1,31 @@
namespace ASC.Common.Caching
namespace ASC.Common.Caching;
public class ProtobufSerializer<T> : ISerializer<T> where T : IMessage<T>, new()
{
public class ProtobufSerializer<T> : ISerializer<T> where T : IMessage<T>, new()
public byte[] Serialize(T data, SerializationContext context)
{
public byte[] Serialize(T data, SerializationContext context)
{
return data.ToByteArray();
}
}
public class ProtobufDeserializer<T> : IDeserializer<T> where T : IMessage<T>, new()
{
private readonly MessageParser<T> parser;
public ProtobufDeserializer()
{
parser = new MessageParser<T>(() => new T());
}
public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
{
return parser.ParseFrom(data.ToArray());
}
}
public static class GuidExtension
{
public static ByteString ToByteString(this Guid id)
{
return ByteString.CopyFrom(id.ToByteArray());
}
public static Guid FromByteString(this ByteString id)
{
return new Guid(id.ToByteArray());
}
return data.ToByteArray();
}
}
public class ProtobufDeserializer<T> : IDeserializer<T> where T : IMessage<T>, new()
{
private readonly MessageParser<T> _parser;
public ProtobufDeserializer()
{
_parser = new MessageParser<T>(() => new T());
}
public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
{
return _parser.ParseFrom(data.ToArray());
}
}
public static class GuidExtension
{
public static ByteString ToByteString(this Guid id) => ByteString.CopyFrom(id.ToByteArray());
public static Guid FromByteString(this ByteString id) => new Guid(id.ToByteArray());
}

View File

@ -17,11 +17,11 @@
namespace ASC.Common.Caching;
[Singletone]
public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
public class RedisCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
{
private readonly IRedisDatabase _redis;
public RedisCache(IRedisCacheClient redisCacheClient)
public RedisCacheNotify(IRedisCacheClient redisCacheClient)
{
_redis = redisCacheClient.GetDbFromConfiguration();
}
@ -53,9 +53,9 @@ public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
.GetResult();
}
private string GetChannelName(CacheNotifyAction cacheNotifyAction)
private string GetChannelName(CacheNotifyAction action)
{
return $"asc:channel:{cacheNotifyAction}:{typeof(T).FullName}".ToLower();
return $"asc:channel:{action}:{typeof(T).FullName}".ToLower();
}
class RedisCachePubSubItem<T0>
@ -64,7 +64,4 @@ public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
public CacheNotifyAction Action { get; set; }
}
}
}

View File

@ -23,124 +23,120 @@
*
*/
namespace ASC.Collections
namespace ASC.Collections;
public abstract class CachedDictionaryBase<T>
{
public abstract class CachedDictionaryBase<T>
protected string BaseKey { get; set; }
protected Func<T, bool> Condition { get; set; }
public T this[string key] => Get(key);
public T this[Func<T> @default] => Get(@default);
protected abstract void InsertRootKey(string rootKey);
public void Clear()
{
protected string baseKey;
protected Func<T, bool> condition;
InsertRootKey(BaseKey);
}
public T this[string key]
public void Clear(string rootKey)
{
InsertRootKey(BuildKey(string.Empty, rootKey));
}
public void Reset(string key)
{
Reset(string.Empty, key);
}
public T Get(string key)
{
return Get(string.Empty, key, null);
}
public T Get(string key, Func<T> defaults)
{
return Get(string.Empty, key, defaults);
}
public void Add(string key, T newValue)
{
Add(string.Empty, key, newValue);
}
public bool HasItem(string key)
{
return !Equals(Get(key), default(T));
}
public T Get(Func<T> @default)
{
var key = string.Format("func {0} {2}.{1}({3})", @default.Method.ReturnType, @default.Method.Name,
@default.Method.DeclaringType.FullName,
string.Join(",",
@default.Method.GetGenericArguments().Select(x => x.FullName).ToArray
()));
return Get(key, @default);
}
public virtual T Get(string rootkey, string key, Func<T> defaults)
{
var fullKey = BuildKey(key, rootkey);
var objectCache = GetObjectFromCache(fullKey);
if (FitsCondition(objectCache))
{
get { return Get(key); }
OnHit(fullKey);
return ReturnCached(objectCache);
}
public T this[Func<T> @default]
if (defaults != null)
{
get { return Get(@default); }
OnMiss(fullKey);
var newValue = defaults();
if (Condition == null || Condition(newValue))
Add(rootkey, key, newValue);
return newValue;
}
protected abstract void InsertRootKey(string rootKey);
return default;
}
public void Clear()
{
InsertRootKey(baseKey);
}
public abstract void Add(string rootkey, string key, T newValue);
public void Clear(string rootKey)
{
InsertRootKey(BuildKey(string.Empty, rootKey));
}
public abstract void Reset(string rootKey, string key);
public void Reset(string key)
{
Reset(string.Empty, key);
}
protected virtual bool FitsCondition(object cached)
{
return cached is T;
}
public abstract void Reset(string rootKey, string key);
protected virtual T ReturnCached(object objectCache)
{
return (T)objectCache;
}
public T Get(string key)
{
return Get(string.Empty, key, null);
}
protected string BuildKey(string key, string rootkey)
{
return $"{BaseKey}-{rootkey}-{key}";
}
public T Get(string key, Func<T> defaults)
{
return Get(string.Empty, key, defaults);
}
protected abstract object GetObjectFromCache(string fullKey);
[Conditional("DEBUG")]
protected virtual void OnHit(string fullKey)
{
Debug.Print("cache hit:{0}", fullKey);
}
public void Add(string key, T newValue)
{
Add(string.Empty, key, newValue);
}
public abstract void Add(string rootkey, string key, T newValue);
public bool HasItem(string key)
{
return !Equals(Get(key), default(T));
}
protected string BuildKey(string key, string rootkey)
{
return $"{baseKey}-{rootkey}-{key}";
}
protected abstract object GetObjectFromCache(string fullKey);
public T Get(Func<T> @default)
{
var key = string.Format("func {0} {2}.{1}({3})", @default.Method.ReturnType, @default.Method.Name,
@default.Method.DeclaringType.FullName,
string.Join(",",
@default.Method.GetGenericArguments().Select(x => x.FullName).ToArray
()));
return Get(key, @default);
}
protected virtual bool FitsCondition(object cached)
{
return cached is T;
}
public virtual T Get(string rootkey, string key, Func<T> defaults)
{
var fullKey = BuildKey(key, rootkey);
var objectCache = GetObjectFromCache(fullKey);
if (FitsCondition(objectCache))
{
OnHit(fullKey);
return ReturnCached(objectCache);
}
if (defaults != null)
{
OnMiss(fullKey);
var newValue = defaults();
if (condition == null || condition(newValue))
{
Add(rootkey, key, newValue);
}
return newValue;
}
return default;
}
protected virtual T ReturnCached(object objectCache)
{
return (T)objectCache;
}
[Conditional("DEBUG")]
protected virtual void OnHit(string fullKey)
{
Debug.Print("cache hit:{0}", fullKey);
}
[Conditional("DEBUG")]
protected virtual void OnMiss(string fullKey)
{
Debug.Print("cache miss:{0}", fullKey);
}
[Conditional("DEBUG")]
protected virtual void OnMiss(string fullKey)
{
Debug.Print("cache miss:{0}", fullKey);
}
}

View File

@ -23,73 +23,68 @@
*
*/
namespace ASC.Collections
{
public sealed class HttpRequestDictionary<T> : CachedDictionaryBase<T>
{
private sealed class CachedItem
{
internal T Value { get; set; }
internal CachedItem(T value)
{
Value = value;
}
namespace ASC.Collections;
public sealed class HttpRequestDictionary<T> : CachedDictionaryBase<T>
{
private readonly HttpContext _httpContext;
public HttpRequestDictionary(HttpContext httpContext, string baseKey)
{
Condition = (T) => true;
BaseKey = baseKey;
_httpContext = httpContext;
}
public override void Reset(string rootKey, string key)
{
if (_httpContext != null)
{
var builtkey = BuildKey(key, rootKey);
_httpContext.Items[builtkey] = null;
}
HttpContext HttpContext { get; set; }
public HttpRequestDictionary(HttpContext httpContext, string baseKey)
{
condition = (T) => true;
this.baseKey = baseKey;
HttpContext = httpContext;
}
protected override void InsertRootKey(string rootKey)
{
//We can't expire in HtppContext in such way
}
public override void Reset(string rootKey, string key)
{
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootKey);
HttpContext.Items[builtkey] = null;
}
}
public override void Add(string rootkey, string key, T newValue)
{
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootkey);
HttpContext.Items[builtkey] = new CachedItem(newValue);
}
}
protected override object GetObjectFromCache(string fullKey)
{
return HttpContext?.Items[fullKey];
}
protected override bool FitsCondition(object cached)
{
return cached is CachedItem;
}
protected override T ReturnCached(object objectCache)
{
return ((CachedItem)objectCache).Value;
}
protected override void OnHit(string fullKey)
{
}
protected override void OnMiss(string fullKey)
{
}
}
}
public override void Add(string rootkey, string key, T newValue)
{
if (_httpContext != null)
{
var builtkey = BuildKey(key, rootkey);
_httpContext.Items[builtkey] = new CachedItem(newValue);
}
}
protected override object GetObjectFromCache(string fullKey)
{
return _httpContext?.Items[fullKey];
}
protected override bool FitsCondition(object cached)
{
return cached is CachedItem;
}
protected override T ReturnCached(object objectCache)
{
return ((CachedItem)objectCache).Value;
}
protected override void OnHit(string fullKey) { }
protected override void OnMiss(string fullKey) { }
protected override void InsertRootKey(string rootKey)
{
//We can't expire in HtppContext in such way
}
private sealed class CachedItem
{
internal T Value { get; set; }
internal CachedItem(T value)
{
Value = value;
}
}
}

View File

@ -1,412 +1,436 @@
namespace ASC.Common
namespace ASC.Common;
public enum DIAttributeEnum
{
public enum DIAttributeEnum
Singletone,
Scope,
Transient
}
public class TransientAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Transient;
public TransientAttribute() { }
public TransientAttribute(Type service) : base(service) { }
public TransientAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
{
Singletone,
Scope,
Transient
}
public class TransientAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Transient; }
public TransientAttribute() { }
public TransientAttribute(Type service) : base(service) { }
public TransientAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
if (implementation != null)
{
if (implementation != null)
{
services.AddTransient(service, implementation);
}
else
{
services.AddTransient(service);
}
services.AddTransient(service, implementation);
}
else
{
services.AddTransient(service);
}
}
}
public class ScopeAttribute : DIAttribute
public class ScopeAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Scope;
public ScopeAttribute() { }
public ScopeAttribute(Type service) : base(service) { }
public ScopeAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Scope; }
public ScopeAttribute() { }
public ScopeAttribute(Type service) : base(service) { }
public ScopeAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
if (implementation != null)
{
if (implementation != null)
{
services.AddScoped(service, implementation);
}
else
{
services.AddScoped(service);
}
services.AddScoped(service, implementation);
}
else
{
services.AddScoped(service);
}
}
}
public class SingletoneAttribute : DIAttribute
public class SingletoneAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Singletone;
public SingletoneAttribute() { }
public SingletoneAttribute(Type service) : base(service) { }
public SingletoneAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Singletone; }
public SingletoneAttribute() { }
public SingletoneAttribute(Type service) : base(service) { }
public SingletoneAttribute(Type service, Type implementation) : base(service, implementation) { }
public override void TryAdd(IServiceCollection services, Type service, Type implementation = null)
if (implementation != null)
{
if (implementation != null)
{
services.AddSingleton(service, implementation);
}
else
{
services.AddSingleton(service);
}
services.AddSingleton(service, implementation);
}
else
{
services.AddSingleton(service);
}
}
}
public abstract class DIAttribute : Attribute
{
public abstract DIAttributeEnum DIAttributeEnum { get; }
public Type Implementation { get; }
public Type Service { get; }
public Type Additional { get; set; }
public abstract class DIAttribute : Attribute
{
public abstract DIAttributeEnum DIAttributeEnum { get; }
public Type Implementation { get; }
public Type Service { get; }
public Type Additional { get; set; }
protected DIAttribute() { }
protected DIAttribute(Type service)
{
Service = service;
}
protected DIAttribute(Type service, Type implementation)
{
Implementation = implementation;
Service = service;
}
public abstract void TryAdd(IServiceCollection services, Type service, Type implementation = null);
{
Service = service;
}
public class DIHelper
protected DIAttribute(Type service, Type implementation)
{
public Dictionary<DIAttributeEnum, List<string>> Services { get; set; }
public List<string> Added { get; set; }
public List<string> Configured { get; set; }
public IServiceCollection ServiceCollection { get; private set; }
Implementation = implementation;
Service = service;
}
public DIHelper()
{
Services = new Dictionary<DIAttributeEnum, List<string>>()
public abstract void TryAdd(IServiceCollection services, Type service, Type implementation = null);
}
public class DIHelper
{
public Dictionary<DIAttributeEnum, List<string>> Services { get; set; }
public List<string> Added { get; set; }
public List<string> Configured { get; set; }
public IServiceCollection ServiceCollection { get; private set; }
public DIHelper()
{
Services = new Dictionary<DIAttributeEnum, List<string>>()
{
{ DIAttributeEnum.Singletone, new List<string>() },
{ DIAttributeEnum.Scope, new List<string>() },
{ DIAttributeEnum.Transient, new List<string>() }
};
Added = new List<string>();
Configured = new List<string>();
}
public DIHelper(IServiceCollection serviceCollection) : this()
Added = new List<string>();
Configured = new List<string>();
}
public DIHelper(IServiceCollection serviceCollection) : this()
{
ServiceCollection = serviceCollection;
}
public void Configure(IServiceCollection serviceCollection)
{
ServiceCollection = serviceCollection;
}
public void RegisterProducts(IConfiguration configuration, string path)
{
var types = AutofacExtension.FindAndLoad(configuration, path);
foreach (var t in types.Select(Type.GetType).Where(r => r != null))
{
ServiceCollection = serviceCollection;
TryAdd(t);
}
}
public void Configure(IServiceCollection serviceCollection)
public bool TryAdd<TService>() where TService : class
{
return TryAdd(typeof(TService));
}
public bool TryAdd<TService, TImplementation>() where TService : class
{
return TryAdd(typeof(TService), typeof(TImplementation));
}
public bool TryAdd(Type service, Type implementation = null)
{
if (service.IsInterface && service.IsGenericType && implementation == null &&
(service.GetGenericTypeDefinition() == typeof(IOptionsSnapshot<>) ||
service.GetGenericTypeDefinition() == typeof(IOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
))
{
ServiceCollection = serviceCollection;
}
service = service.GetGenericArguments().FirstOrDefault();
public void RegisterProducts(IConfiguration configuration, string path)
{
var types = AutofacExtension.FindAndLoad(configuration, path);
foreach (var t in types.Select(Type.GetType).Where(r => r != null))
if (service == null)
{
TryAdd(t);
return false;
}
}
public bool TryAdd<TService>() where TService : class
var serviceName = $"{service}{implementation}";
if (Added.Contains(serviceName))
{
return TryAdd(typeof(TService));
return false;
}
public bool TryAdd<TService, TImplementation>() where TService : class
{
return TryAdd(typeof(TService), typeof(TImplementation));
}
Added.Add(serviceName);
public bool TryAdd(Type service, Type implementation = null)
var di = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var isnew = false;
if (di != null)
{
if (service.IsInterface && service.IsGenericType && implementation == null &&
(service.GetGenericTypeDefinition() == typeof(IOptionsSnapshot<>) ||
service.GetGenericTypeDefinition() == typeof(IOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
))
if (di.Additional != null)
{
service = service.GetGenericArguments().FirstOrDefault();
if (service == null)
var m = di.Additional.GetMethod("Register", BindingFlags.Public | BindingFlags.Static);
m.Invoke(null, new[] { this });
}
if (!service.IsInterface || implementation != null)
{
isnew = implementation != null ? Register(service, implementation) : Register(service);
if (!isnew)
{
return false;
}
}
var serviceName = $"{service}{implementation}";
if (Added.Contains(serviceName)) return false;
Added.Add(serviceName);
var di = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var isnew = false;
if (di != null)
if (service.IsInterface && implementation == null || !service.IsInterface)
{
if (di.Additional != null)
if (di.Service != null)
{
var m = di.Additional.GetMethod("Register", BindingFlags.Public | BindingFlags.Static);
m.Invoke(null, new[] { this });
}
var a = di.Service.GetInterfaces().FirstOrDefault(x => x.IsGenericType && (
x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
));
if (!service.IsInterface || implementation != null)
{
isnew = implementation != null ? Register(service, implementation) : Register(service);
if (!isnew) return false;
}
if (service.IsInterface && implementation == null || !service.IsInterface)
{
if (di.Service != null)
if (a != null)
{
var a = di.Service.GetInterfaces().FirstOrDefault(x => x.IsGenericType && (
x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
));
if (a != null)
if (!a.ContainsGenericParameters)
{
if (!a.ContainsGenericParameters)
{
var b = a.GetGenericArguments();
var b = a.GetGenericArguments();
foreach (var g in b)
foreach (var g in b)
{
if (g != service)
{
if (g != service)
TryAdd(g);
if (service.IsInterface && di.Implementation == null)
{
TryAdd(g);
if (service.IsInterface && di.Implementation == null)
{
TryAdd(service, g);
}
TryAdd(service, g);
}
}
TryAdd(a, di.Service);
}
else
{
Type c;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Service.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
TryAdd(a, di.Service);
}
else
{
if (di.Implementation == null)
Type c;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
isnew = Register(service, di.Service);
TryAdd(di.Service);
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
Register(di.Service);
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Service.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
}
if (di.Implementation != null)
else
{
var a = di.Implementation.GetInterfaces().FirstOrDefault(x => x.IsGenericType &&
(x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>))
);
if (a != null)
if (di.Implementation == null)
{
if (!a.ContainsGenericParameters)
{
var b = a.GetGenericArguments();
foreach (var g in b)
{
if (g != service)
{
//TryAdd(g);
if (service.IsInterface && implementation == null)
{
TryAdd(service, g);
}
}
}
TryAdd(a, di.Implementation);
}
else
{
Type c;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Implementation.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
isnew = Register(service, di.Service);
TryAdd(di.Service);
}
else
{
isnew = TryAdd(service, di.Implementation);
Register(di.Service);
}
}
}
}
if (isnew)
{
ConstructorInfo[] props = null;
if (!service.IsInterface)
if (di.Implementation != null)
{
props = service.GetConstructors();
}
else if (implementation != null)
{
props = implementation.GetConstructors();
}
else if (di.Service != null)
{
props = di.Service.GetConstructors();
}
if (props != null)
{
var par = props.SelectMany(r => r.GetParameters()).Distinct();
foreach (var p1 in par)
var a = di.Implementation.GetInterfaces().FirstOrDefault(x => x.IsGenericType &&
(x.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>))
);
if (a != null)
{
TryAdd(p1.ParameterType);
if (!a.ContainsGenericParameters)
{
var b = a.GetGenericArguments();
foreach (var g in b)
{
if (g != service)
{
//TryAdd(g);
if (service.IsInterface && implementation == null)
{
TryAdd(service, g);
}
}
}
TryAdd(a, di.Implementation);
}
else
{
Type c;
var a1 = a.GetGenericTypeDefinition();
var b = a.GetGenericArguments().FirstOrDefault();
if (b != null && b.IsGenericType)
{
var b1 = b.GetGenericTypeDefinition().MakeGenericType(service.GetGenericArguments());
TryAdd(b1);
c = a1.MakeGenericType(b1);
}
else
{
c = a1.MakeGenericType(service.GetGenericArguments());
}
TryAdd(c, di.Implementation.MakeGenericType(service.GetGenericArguments()));
//a, di.Service
}
}
else
{
isnew = TryAdd(service, di.Implementation);
}
}
}
return isnew;
}
private bool Register(Type service, Type implementation = null)
if (isnew)
{
if (service.IsSubclassOf(typeof(ControllerBase)) || service.GetInterfaces().Contains(typeof(IResourceFilter)) || service.GetInterfaces().Contains(typeof(IDictionary<string, string>))) return true;
var c = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var serviceName = $"{service}{implementation}";
ConstructorInfo[] props = null;
if (!Services[c.DIAttributeEnum].Contains(serviceName))
if (!service.IsInterface)
{
c.TryAdd(ServiceCollection, service, implementation);
Services[c.DIAttributeEnum].Add(serviceName);
return true;
props = service.GetConstructors();
}
else if (implementation != null)
{
props = implementation.GetConstructors();
}
else if (di.Service != null)
{
props = di.Service.GetConstructors();
}
return false;
}
public DIHelper TryAddSingleton<TService>(Func<IServiceProvider, TService> implementationFactory) where TService : class
{
var serviceName = $"{typeof(TService)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
if (props != null)
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton(implementationFactory);
}
var par = props.SelectMany(r => r.GetParameters()).Distinct();
return this;
foreach (var p1 in par)
{
TryAdd(p1.ParameterType);
}
}
}
public DIHelper TryAddSingleton<TService, TImplementation>() where TService : class where TImplementation : class, TService
{
var serviceName = $"{typeof(TService)}{typeof(TImplementation)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton<TService, TImplementation>();
}
return this;
}
public DIHelper Configure<TOptions>(Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(configureOptions);
}
return this;
}
public DIHelper Configure<TOptions>(string name, Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}{name}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(name, configureOptions);
}
return this;
}
return isnew;
}
}
public DIHelper TryAddSingleton<TService>(Func<IServiceProvider, TService> implementationFactory) where TService : class
{
var serviceName = $"{typeof(TService)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton(implementationFactory);
}
return this;
}
public DIHelper TryAddSingleton<TService, TImplementation>() where TService : class where TImplementation : class, TService
{
var serviceName = $"{typeof(TService)}{typeof(TImplementation)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
ServiceCollection.TryAddSingleton<TService, TImplementation>();
}
return this;
}
public DIHelper Configure<TOptions>(Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(configureOptions);
}
return this;
}
public DIHelper Configure<TOptions>(string name, Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}{name}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
ServiceCollection.Configure(name, configureOptions);
}
return this;
}
private bool Register(Type service, Type implementation = null)
{
if (service.IsSubclassOf(typeof(ControllerBase)) || service.GetInterfaces().Contains(typeof(IResourceFilter))
|| service.GetInterfaces().Contains(typeof(IDictionary<string, string>)))
{
return true;
}
var c = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var serviceName = $"{service}{implementation}";
if (!Services[c.DIAttributeEnum].Contains(serviceName))
{
c.TryAdd(ServiceCollection, service, implementation);
Services[c.DIAttributeEnum].Add(serviceName);
return true;
}
return false;
}
}

View File

@ -22,27 +22,26 @@
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
namespace ASC.Common.Data
namespace ASC.Common.Data;
public static class StreamExtension
{
public static class StreamExtension
{
public const int BufferSize = 2048; //NOTE: set to 2048 to fit in minimum tcp window
public static void StreamCopyTo(this Stream srcStream, Stream dstStream, int length)
{
if (srcStream == null) throw new ArgumentNullException(nameof(srcStream));
if (dstStream == null) throw new ArgumentNullException(nameof(dstStream));
if (srcStream == null) throw new ArgumentNullException(nameof(srcStream));
if (dstStream == null) throw new ArgumentNullException(nameof(dstStream));
var buffer = new byte[BufferSize];
int totalRead = 0;
int readed;
while ((readed = srcStream.Read(buffer, 0, length - totalRead > BufferSize ? BufferSize : length - totalRead)) > 0 && totalRead < length)
{
dstStream.Write(buffer, 0, readed);
totalRead += readed;
}
}
}
}
}

View File

@ -14,70 +14,71 @@
*
*/
namespace System.IO
namespace System.IO;
[Singletone]
public class TempPath
{
[Singletone]
public class TempPath
private readonly string _tempFolder;
public TempPath(IConfiguration configuration)
{
readonly string tempFolder;
public TempPath(IConfiguration configuration)
string rootFolder = AppContext.BaseDirectory;
if (string.IsNullOrEmpty(rootFolder))
{
string rootFolder = AppContext.BaseDirectory;
if (string.IsNullOrEmpty(rootFolder))
{
rootFolder = Assembly.GetEntryAssembly().Location;
}
tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
if (!Path.IsPathRooted(tempFolder))
{
tempFolder = Path.GetFullPath(Path.Combine(rootFolder, tempFolder));
}
if (!Directory.Exists(tempFolder))
{
Directory.CreateDirectory(tempFolder);
}
rootFolder = Assembly.GetEntryAssembly().Location;
}
public string GetTempPath()
_tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
if (!Path.IsPathRooted(_tempFolder))
{
return tempFolder;
_tempFolder = Path.GetFullPath(Path.Combine(rootFolder, _tempFolder));
}
public string GetTempFileName()
if (!Directory.Exists(_tempFolder))
{
FileStream f = null;
string path;
var count = 0;
do
{
path = Path.Combine(tempFolder, Path.GetRandomFileName());
try
{
using (f = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read))
{
return path;
}
}
catch (IOException ex)
{
if (ex.HResult != -2147024816 || count++ > 65536)
throw;
}
catch (UnauthorizedAccessException ex)
{
if (count++ > 65536)
throw new IOException(ex.Message, ex);
}
} while (f == null);
return path;
Directory.CreateDirectory(_tempFolder);
}
}
}
public string GetTempPath()
{
return _tempFolder;
}
public string GetTempFileName()
{
FileStream f = null;
string path;
var count = 0;
do
{
path = Path.Combine(_tempFolder, Path.GetRandomFileName());
try
{
using (f = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read))
{
return path;
}
}
catch (IOException ex)
{
if (ex.HResult != -2147024816 || count++ > 65536)
{
throw;
}
}
catch (UnauthorizedAccessException ex)
{
if (count++ > 65536)
{
throw new IOException(ex.Message, ex);
}
}
} while (f == null);
return path;
}
}

View File

@ -14,35 +14,37 @@
*
*/
namespace ASC.Common
namespace ASC.Common;
[Singletone]
public class TempStream
{
[Singletone]
public class TempStream
private readonly TempPath _tempPath;
public TempStream(TempPath tempPath)
{
private TempPath TempPath { get; }
_tempPath = tempPath;
}
public TempStream(TempPath tempPath)
{
TempPath = tempPath;
}
public Stream GetBuffered(Stream srcStream)
{
public Stream GetBuffered(Stream srcStream)
{
if (srcStream == null) throw new ArgumentNullException(nameof(srcStream));
if (!srcStream.CanSeek || srcStream.CanTimeout)
{
//Buffer it
var memStream = Create();
srcStream.CopyTo(memStream);
memStream.Position = 0;
return memStream;
}
return srcStream;
if (!srcStream.CanSeek || srcStream.CanTimeout)
{
//Buffer it
var memStream = Create();
srcStream.CopyTo(memStream);
memStream.Position = 0;
return memStream;
}
public Stream Create()
{
return new FileStream(TempPath.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
}
return srcStream;
}
public Stream Create()
{
return new FileStream(_tempPath.GetTempFileName(), FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
}
}

View File

@ -1,154 +1,162 @@
namespace ASC.Common.DependencyInjection
{
internal class AutofacComponent
{
public string Type { get; set; }
public IEnumerable<AutofacService> Services { get; set; }
}
internal class AutofacService
{
public string Type { get; set; }
}
namespace ASC.Common.DependencyInjection;
public static class AutofacExtension
internal class AutofacComponent
{
public string Type { get; set; }
public IEnumerable<AutofacService> Services { get; set; }
}
internal class AutofacService
{
public string Type { get; set; }
}
public static class AutofacExtension
{
public static void Register(this ContainerBuilder builder, IConfiguration configuration,
bool loadproducts = true, bool loadconsumers = true, params string[] intern)
{
public static void Register(this ContainerBuilder builder, IConfiguration configuration, bool loadproducts = true, bool loadconsumers = true, params string[] intern)
{
var modules = new List<(bool, string)>
var modules = new List<(bool, string)>
{
(true, "autofac.json")
};
if (loadproducts)
{
modules.Add((true, "autofac.products.json"));
}
if (loadconsumers)
{
modules.Add((true, "autofac.consumers.json"));
}
if (intern != null)
{
modules.AddRange(intern.Select(r => (false, r)));
}
foreach (var p in modules)
{
var config = new ConfigurationBuilder();
if (p.Item1)
{
config.SetBasePath(configuration["pathToConf"]);
}
config.AddJsonFile(p.Item2);
var root = config.Build();
var module = new ConfigurationModule(root);
builder.RegisterModule(module);
}
return;
if (loadproducts)
{
modules.Add((true, "autofac.products.json"));
}
public static List<string> FindAndLoad(IConfiguration configuration, string currentDir, string section = "autofac.products.json")
if (loadconsumers)
{
modules.Add((true, "autofac.consumers.json"));
}
if (intern != null)
{
modules.AddRange(intern.Select(r => (false, r)));
}
foreach (var p in modules)
{
var config = new ConfigurationBuilder();
config.SetBasePath(configuration["pathToConf"]);
config.AddJsonFile(section);
var root = config.Build();
var sectionSettings = root.GetSection("components");
if (sectionSettings == null)
if (p.Item1)
{
return new List<string>();
config.SetBasePath(configuration["pathToConf"]);
}
var folder = configuration["core:products:folder"];
var subfolder = configuration["core:products:subfolder"];
string productsDir;
config.AddJsonFile(p.Item2);
if (!Path.IsPathRooted(folder))
var root = config.Build();
var module = new ConfigurationModule(root);
builder.RegisterModule(module);
}
return;
}
public static List<string> FindAndLoad(IConfiguration configuration, string currentDir, string section = "autofac.products.json")
{
var config = new ConfigurationBuilder();
config.SetBasePath(configuration["pathToConf"]);
config.AddJsonFile(section);
var root = config.Build();
var sectionSettings = root.GetSection("components");
if (sectionSettings == null)
{
return new List<string>();
}
var folder = configuration["core:products:folder"];
var subfolder = configuration["core:products:subfolder"];
string productsDir;
if (!Path.IsPathRooted(folder))
{
if (currentDir.EndsWith(CrossPlatform.PathCombine(Path.GetFileName(folder), Assembly.GetEntryAssembly().GetName().Name, subfolder)))
{
if (currentDir.EndsWith(CrossPlatform.PathCombine(Path.GetFileName(folder), Assembly.GetEntryAssembly().GetName().Name, subfolder)))
{
productsDir = Path.GetFullPath(CrossPlatform.PathCombine("..", ".."));
}
else
{
productsDir = Path.GetFullPath(CrossPlatform.PathCombine(currentDir, folder));
}
productsDir = Path.GetFullPath(CrossPlatform.PathCombine("..", ".."));
}
else
{
productsDir = folder;
productsDir = Path.GetFullPath(CrossPlatform.PathCombine(currentDir, folder));
}
}
else
{
productsDir = folder;
}
var cs = new List<AutofacComponent>();
sectionSettings.Bind(cs);
var cs = new List<AutofacComponent>();
sectionSettings.Bind(cs);
var types = new List<string>();
var types = new List<string>();
foreach (var component in cs)
foreach (var component in cs)
{
try
{
try
{
LoadAssembly(component.Type);
types.Add(component.Type);
}
catch (System.Exception)
{
//TODO
}
LoadAssembly(component.Type);
types.Add(component.Type);
}
return types;
void LoadAssembly(string type)
catch (System.Exception)
{
//TODO
}
}
return types;
void LoadAssembly(string type)
{
var dll = type.Substring(type.IndexOf(',') + 1).Trim();
var path = GetFullPath(dll);
var path = GetFullPath(dll);
if (!string.IsNullOrEmpty(path))
{
AssemblyLoadContext.Default.Resolving += new Resolver(path).Resolving;
}
}
string GetFullPath(string n)
if (!string.IsNullOrEmpty(path))
{
var productPath = CrossPlatform.PathCombine(productsDir, n, subfolder);
return GetPath(CrossPlatform.PathCombine(productPath, "bin"), n, SearchOption.AllDirectories) ?? GetPath(productPath, n, SearchOption.TopDirectoryOnly);
}
static string GetPath(string dirPath, string dll, SearchOption searchOption)
{
if (!Directory.Exists(dirPath)) return null;
return Directory.GetFiles(dirPath, $"{dll}.dll", searchOption).FirstOrDefault();
AssemblyLoadContext.Default.Resolving += new Resolver(path).Resolving;
}
}
}
class Resolver
{
private string ResolvePath { get; set; }
public Resolver(string assemblyPath)
string GetFullPath(string n)
{
ResolvePath = assemblyPath;
var productPath = CrossPlatform.PathCombine(productsDir, n, subfolder);
return GetPath(CrossPlatform.PathCombine(productPath, "bin"), n, SearchOption.AllDirectories)
?? GetPath(productPath, n, SearchOption.TopDirectoryOnly);
}
public Assembly Resolving(AssemblyLoadContext context, AssemblyName assemblyName)
static string GetPath(string dirPath, string dll, SearchOption searchOption)
{
var path = CrossPlatform.PathCombine(Path.GetDirectoryName(ResolvePath), $"{assemblyName.Name}.dll");
if (!Directory.Exists(dirPath))
{
return null;
}
if (!File.Exists(path)) return null;
return context.LoadFromAssemblyPath(path);
return Directory.GetFiles(dirPath, $"{dll}.dll", searchOption).FirstOrDefault();
}
}
}
class Resolver
{
private readonly string _resolvePath;
public Resolver(string assemblyPath)
{
_resolvePath = assemblyPath;
}
public Assembly Resolving(AssemblyLoadContext context, AssemblyName assemblyName)
{
var path = CrossPlatform.PathCombine(Path.GetDirectoryName(_resolvePath), $"{assemblyName.Name}.dll");
if (!File.Exists(path))
{
return null;
}
return context.LoadFromAssemblyPath(path);
}
}

View File

@ -23,30 +23,23 @@
*
*/
namespace ASC.Geolocation
{
public class IPGeolocationInfo
{
public string Key { get; set; }
public string City { get; set; }
namespace ASC.Geolocation;
public double TimezoneOffset { get; set; }
public class IPGeolocationInfo
{
public string Key { get; set; }
public string City { get; set; }
public double TimezoneOffset { get; set; }
public string TimezoneName { get; set; }
public string IPStart { get; set; }
public string IPEnd { get; set; }
public string TimezoneName { get; set; }
public string IPStart { get; set; }
public string IPEnd { get; set; }
public readonly static IPGeolocationInfo Default = new IPGeolocationInfo
{
Key = string.Empty,
IPStart = string.Empty,
IPEnd = string.Empty,
City = string.Empty,
TimezoneName = string.Empty,
};
}
public readonly static IPGeolocationInfo Default = new IPGeolocationInfo
{
Key = string.Empty,
IPStart = string.Empty,
IPEnd = string.Empty,
City = string.Empty,
TimezoneName = string.Empty,
};
}

View File

@ -21,6 +21,8 @@ global using System.Threading.Tasks;
global using System.Web;
global using System.Xml.Linq;
global using System.Xml.XPath;
global using System.ServiceModel;
global using System.Runtime.Serialization;
global using ARSoft.Tools.Net;
global using ARSoft.Tools.Net.Dns;

View File

@ -1,92 +1,93 @@
using ILogger = Microsoft.Extensions.Logging.ILogger;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace ASC.Common.Logging
namespace ASC.Common.Logging;
[Singletone]
public class EFLoggerFactory : ILoggerFactory
{
[Singletone]
public class EFLoggerFactory : ILoggerFactory
private readonly Lazy<ILogger> _logger;
private readonly ILoggerProvider _loggerProvider;
public EFLoggerFactory(EFLoggerProvider loggerProvider)
{
Lazy<ILogger> Logger { get; set; }
ILoggerProvider LoggerProvider { get; set; }
public EFLoggerFactory(EFLoggerProvider loggerProvider)
{
LoggerProvider = loggerProvider;
Logger = new Lazy<ILogger>(() => LoggerProvider.CreateLogger(""));
}
public void AddProvider(ILoggerProvider provider)
{
//LoggerProvider = provider;
}
public ILogger CreateLogger(string categoryName)
{
return Logger.Value;
}
public void Dispose()
{
}
_loggerProvider = loggerProvider;
_logger = new Lazy<ILogger>(() => _loggerProvider.CreateLogger(""));
}
[Singletone]
public class EFLoggerProvider : ILoggerProvider
public void AddProvider(ILoggerProvider provider)
{
private IOptionsMonitor<ILog> Option { get; }
public EFLoggerProvider(IOptionsMonitor<ILog> option)
{
Option = option;
}
public ILogger CreateLogger(string categoryName)
{
return new EFLogger(Option.Get("ASC.SQL"));
}
public void Dispose() { }
//LoggerProvider = provider;
}
public class EFLogger : ILogger
public ILogger CreateLogger(string categoryName)
{
public ILog CustomLogger { get; }
return _logger.Value;
}
public EFLogger(ILog customLogger)
public void Dispose() { }
}
[Singletone]
public class EFLoggerProvider : ILoggerProvider
{
private readonly IOptionsMonitor<ILog> _option;
public EFLoggerProvider(IOptionsMonitor<ILog> option)
{
_option = option;
}
public ILogger CreateLogger(string categoryName)
{
return new EFLogger(_option.Get("ASC.SQL"));
}
public void Dispose() { }
}
public class EFLogger : ILogger
{
public ILog CustomLogger { get; }
public EFLogger(ILog customLogger)
{
CustomLogger = customLogger;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel switch
{
CustomLogger = customLogger;
}
LogLevel.Trace => CustomLogger.IsTraceEnabled,
LogLevel.Information => CustomLogger.IsInfoEnabled,
LogLevel.None => false,
public IDisposable BeginScope<TState>(TState state) { return null; }
public bool IsEnabled(LogLevel logLevel)
LogLevel.Debug => CustomLogger.IsDebugEnabled,
LogLevel.Warning => CustomLogger.IsWarnEnabled,
LogLevel.Error => CustomLogger.IsErrorEnabled,
LogLevel.Critical => CustomLogger.IsErrorEnabled,
_ => true,
};
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
switch (eventId.Id)
{
return logLevel switch
{
LogLevel.Trace => CustomLogger.IsTraceEnabled,
LogLevel.Information => CustomLogger.IsInfoEnabled,
LogLevel.None => false,
LogLevel.Debug => CustomLogger.IsDebugEnabled,
LogLevel.Warning => CustomLogger.IsWarnEnabled,
LogLevel.Error => CustomLogger.IsErrorEnabled,
LogLevel.Critical => CustomLogger.IsErrorEnabled,
_ => true,
};
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
switch (eventId.Id)
{
//case 20000:
// CustomLogger.Debug(formatter(state, exception));
// break;
case 20101:
var keyValuePairs = state as IEnumerable<KeyValuePair<string, object>>;
CustomLogger.DebugWithProps("", keyValuePairs);
break;
}
//case 20000:
// CustomLogger.Debug(formatter(state, exception));
// break;
case 20101:
var keyValuePairs = state as IEnumerable<KeyValuePair<string, object>>;
CustomLogger.DebugWithProps("", keyValuePairs);
break;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -23,87 +23,89 @@
*
*/
namespace ASC.Common.Logging
{
public class SelfCleaningAppender : RollingFileAppender
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
return _cleanPeriod.Value;
const string key = "CleanPeriod";
var value = 30;
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null && repo.Properties.GetKeys().Contains(key))
{
int.TryParse(repo.Properties[key].ToString(), out value);
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
try
{
if (string.IsNullOrEmpty(File))
return;
namespace ASC.Common.Logging;
var fileInfo = new FileInfo(File);
if (!fileInfo.Exists)
return;
var directory = fileInfo.Directory;
if (directory == null || !directory.Exists)
return;
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
LogLog.Error(GetType(), err.Message, err);
}
}
protected override void Append(LoggingEvent loggingEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
public class SelfCleaningAppender : RollingFileAppender
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
base.Append(loggingEvent);
protected override void Append(LoggingEvent loggingEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
protected override void Append(LoggingEvent[] loggingEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
base.Append(loggingEvent);
}
protected override void Append(LoggingEvent[] loggingEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
base.Append(loggingEvents);
}
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
{
return _cleanPeriod.Value;
}
const string key = "CleanPeriod";
var value = 30;
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null && repo.Properties.GetKeys().Contains(key))
{
int.TryParse(repo.Properties[key].ToString(), out value);
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
try
{
if (string.IsNullOrEmpty(File))
{
return;
}
base.Append(loggingEvents);
}
}
var fileInfo = new FileInfo(File);
if (!fileInfo.Exists)
{
return;
}
var directory = fileInfo.Directory;
if (directory == null || !directory.Exists)
{
return;
}
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
LogLog.Error(GetType(), err.Message, err);
}
}
}

View File

@ -25,116 +25,125 @@
using LogLevel = NLog.LogLevel;
namespace ASC.Common.Logging
{
[Target("SelfCleaning")]
public class SelfCleaningTarget : FileTarget
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
return _cleanPeriod.Value;
var value = 30;
const string key = "cleanPeriod";
if (LogManager.Configuration.Variables.TryGetValue(key, out var variable))
{
if (variable != null && !string.IsNullOrEmpty(variable.Text))
{
int.TryParse(variable.Text, out value);
}
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
var filePath = string.Empty;
var dirPath = string.Empty;
try
{
if (FileName == null)
return;
filePath = ((NLog.Layouts.SimpleLayout)FileName).Text;
if (string.IsNullOrEmpty(filePath))
return;
dirPath = Path.GetDirectoryName(filePath);
if (string.IsNullOrEmpty(dirPath))
return;
if (!Path.IsPathRooted(dirPath))
dirPath = CrossPlatform.PathCombine(AppDomain.CurrentDomain.BaseDirectory, dirPath);
var directory = new DirectoryInfo(dirPath);
if (!directory.Exists)
return;
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
base.Write(new LogEventInfo
{
Exception = err,
Level = LogLevel.Error,
Message = $"file: {filePath}, dir: {dirPath}, mess: {err.Message}",
LoggerName = "SelfCleaningTarget"
});
}
}
protected override void Write(IList<AsyncLogEventInfo> logEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
namespace ASC.Common.Logging;
var buffer = new List<AsyncLogEventInfo>();
[Target("SelfCleaning")]
public class SelfCleaningTarget : FileTarget
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
foreach (var logEvent in logEvents)
protected override void Write(IList<AsyncLogEventInfo> logEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
var buffer = new List<AsyncLogEventInfo>();
foreach (var logEvent in logEvents)
{
buffer.Add(logEvent);
if (buffer.Count < 10)
{
buffer.Add(logEvent);
if (buffer.Count < 10) continue;
base.Write(buffer);
buffer.Clear();
continue;
}
base.Write(buffer);
base.Write(buffer);
buffer.Clear();
}
protected override void Write(LogEventInfo logEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
base.Write(logEvent);
base.Write(buffer);
}
protected override void Write(LogEventInfo logEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
}
base.Write(logEvent);
}
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
{
return _cleanPeriod.Value;
}
var value = 30;
const string key = "cleanPeriod";
if (LogManager.Configuration.Variables.TryGetValue(key, out var variable))
{
if (variable != null && !string.IsNullOrEmpty(variable.Text))
{
int.TryParse(variable.Text, out value);
}
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
var filePath = string.Empty;
var dirPath = string.Empty;
try
{
if (FileName == null)
{
return;
}
filePath = ((NLog.Layouts.SimpleLayout)FileName).Text;
if (string.IsNullOrEmpty(filePath))
{
return;
}
dirPath = Path.GetDirectoryName(filePath);
if (string.IsNullOrEmpty(dirPath))
{
return;
}
if (!Path.IsPathRooted(dirPath))
{
dirPath = CrossPlatform.PathCombine(AppDomain.CurrentDomain.BaseDirectory, dirPath);
}
var directory = new DirectoryInfo(dirPath);
if (!directory.Exists)
{
return;
}
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
base.Write(new LogEventInfo
{
Exception = err,
Level = LogLevel.Error,
Message = $"file: {filePath}, dir: {dirPath}, mess: {err.Message}",
LoggerName = "SelfCleaningTarget"
});
}
}
}

View File

@ -23,72 +23,74 @@
*
*/
namespace ASC.Common.Logging
{
public class SpecialFolderPathConverter : PatternConverter
{
protected override void Convert(TextWriter writer, object state)
{
if (string.IsNullOrEmpty(Option))
{
return;
}
try
{
var result = string.Empty;
const string CMD_LINE = "CommandLine:";
if (Option.StartsWith(CMD_LINE))
{
var args = Environment.CommandLine.Split(' ');
for (var i = 0; i < args.Length - 1; i++)
{
namespace ASC.Common.Logging;
public class SpecialFolderPathConverter : PatternConverter
{
protected override void Convert(TextWriter writer, object state)
{
if (string.IsNullOrEmpty(Option))
{
return;
}
try
{
var result = string.Empty;
const string CMD_LINE = "CommandLine:";
if (Option.StartsWith(CMD_LINE))
{
var args = Environment.CommandLine.Split(' ');
for (var i = 0; i < args.Length - 1; i++)
{
if (args[i].Contains(Option, StringComparison.InvariantCultureIgnoreCase))
{
result = args[i + 1];
}
}
}
else
{
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null)
{
var realKey = Option;
foreach (var key in repo.Properties.GetKeys())
{
if (Path.DirectorySeparatorChar == '/' && key == "UNIX:" + Option)
{
realKey = "UNIX:" + Option;
}
if (Path.DirectorySeparatorChar == '\\' && key == "WINDOWS:" + Option)
{
realKey = "WINDOWS:" + Option;
}
}
var val = repo.Properties[realKey];
if (val is PatternString patternString)
{
patternString.ActivateOptions();
patternString.Format(writer);
}
else if (val != null)
{
result = val.ToString();
}
}
}
if (!string.IsNullOrEmpty(result))
{
result = result.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
writer.Write(result);
}
}
catch (Exception err)
{
LogLog.Error(GetType(), "Can not convert " + Option, err);
}
}
}
}
{
result = args[i + 1];
}
}
}
else
{
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null)
{
var realKey = Option;
foreach (var key in repo.Properties.GetKeys())
{
if (Path.DirectorySeparatorChar == '/' && key == "UNIX:" + Option)
{
realKey = "UNIX:" + Option;
}
if (Path.DirectorySeparatorChar == '\\' && key == "WINDOWS:" + Option)
{
realKey = "WINDOWS:" + Option;
}
}
var val = repo.Properties[realKey];
if (val is PatternString patternString)
{
patternString.ActivateOptions();
patternString.Format(writer);
}
else if (val != null)
{
result = val.ToString();
}
}
}
if (!string.IsNullOrEmpty(result))
{
result = result.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
writer.Write(result);
}
}
catch (Exception err)
{
LogLog.Error(GetType(), "Can not convert " + Option, err);
}
}
}

View File

@ -23,10 +23,12 @@
*
*/
namespace ASC.Common.Mapping
namespace ASC.Common.Mapping;
public interface IMapFrom<T>
{
public interface IMapFrom<T>
void Mapping(Profile profile)
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
profile.CreateMap(typeof(T), GetType());
}
}

View File

@ -23,33 +23,31 @@
*
*/
namespace ASC.Common.Mapping
namespace ASC.Common.Mapping;
public class MappingProfile : Profile
{
public class MappingProfile : Profile
public MappingProfile() => Array.ForEach(AppDomain.CurrentDomain.GetAssemblies(), a => ApplyMappingsFromAssembly(a));
private void ApplyMappingsFromAssembly(Assembly assembly)
{
public MappingProfile()
if (!assembly.GetName().Name.StartsWith("ASC."))
{
Array.ForEach(AppDomain.CurrentDomain.GetAssemblies(), a => ApplyMappingsFromAssembly(a));
return;
}
private void ApplyMappingsFromAssembly(Assembly assembly)
{
if (!assembly.GetName().Name.StartsWith("ASC.")) return;
var types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Any(i =>
var types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Any(i =>
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)));
foreach (var type in types)
{
var instance = Activator.CreateInstance(type);
foreach (var type in types)
{
var instance = Activator.CreateInstance(type);
var methodInfo = type.GetMethod("Mapping")
?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");
var methodInfo = type.GetMethod("Mapping")
?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");
methodInfo?.Invoke(instance, new object[] { this });
}
methodInfo?.Invoke(instance, new object[] { this });
}
}
}
}

View File

@ -23,37 +23,31 @@
*
*/
namespace ASC.Common.Module;
using System.ServiceModel;
namespace ASC.Common.Module
public class BaseWcfClient<TService> : ClientBase<TService>, IDisposable where TService : class
{
public class BaseWcfClient<TService> : ClientBase<TService>, IDisposable where TService : class
{
public BaseWcfClient()
{
}
public BaseWcfClient() { }
void IDisposable.Dispose()
void IDisposable.Dispose()
{
// msdn recommendation to close wcf client
try
{
// msdn recommendation to close wcf client
try
{
//Close();
}
catch (CommunicationException)
{
Abort();
}
catch (TimeoutException)
{
Abort();
}
catch (Exception)
{
Abort();
throw;
}
//Close();
}
catch (CommunicationException)
{
Abort();
}
catch (TimeoutException)
{
Abort();
}
catch (Exception)
{
Abort();
throw;
}
}
}
}

View File

@ -24,12 +24,11 @@
*/
namespace ASC.Common.Module
{
public interface IServiceController
{
void Start();
namespace ASC.Common.Module;
void Stop();
}
public interface IServiceController
{
void Start();
void Stop();
}

View File

@ -1,192 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading;
using ASC.Common.Utils;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using log4net;
namespace ASC.Common.Notify
{
public class AWSEmail
{
public enum SendStatus
{
Ok,
Failed,
QuotaLimit
}
private readonly AmazonSimpleEmailServiceClient _emailService;
private readonly ILog _log = LogHolder.Log("ASC.Notify.AmazonSES");
//Static fields
private static readonly TimeSpan RefreshTimeout;
private static DateTime _lastRefresh;
private static DateTime _lastSend;
private static TimeSpan _sendWindow = TimeSpan.MinValue;
private static GetSendQuotaResult _quota;
private static readonly object SynchRoot = new object();
static AWSEmail()
{
RefreshTimeout = TimeSpan.FromMinutes(30);
if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["ses.refreshTimeout"]))
{
TimeSpan.TryParse(ConfigurationManager.AppSettings["ses.refreshTimeout"], out RefreshTimeout);
}
_lastRefresh = DateTime.UtcNow - RefreshTimeout;//Set to refresh on first send
}
public AWSEmail()
{
var accessKey = ConfigurationManager.AppSettings["ses.accessKey"];
var secretKey = ConfigurationManager.AppSettings["ses.secretKey"];
_emailService = new AmazonSimpleEmailServiceClient(accessKey, secretKey);
}
public SendStatus SendEmail(MailMessage mailMessage)
{
//Check if we need to query stats
RefreshQuotaIfNeeded();
if (_quota != null)
{
lock (SynchRoot)
{
if (_quota.Max24HourSend <= _quota.SentLast24Hours)
{
//Quota exceeded
//Queu next refresh to +24 hours
_lastRefresh = DateTime.UtcNow.AddHours(24);
_log.WarnFormat("quota limit reached. setting next check to: {0}", _lastRefresh);
return SendStatus.QuotaLimit;
}
}
}
var destination = new Destination
{
ToAddresses = mailMessage.To.Select(adresses => adresses.Address).ToList(),
BccAddresses = mailMessage.Bcc.Select(adresses => adresses.Address).ToList(),
CcAddresses = mailMessage.CC.Select(adresses => adresses.Address).ToList(),
};
var body = new Body(new Content(mailMessage.Body) { Charset = Encoding.UTF8.WebName });
if (mailMessage.AlternateViews.Count > 0)
{
//Get html body
foreach (var alternateView in mailMessage.AlternateViews)
{
if ("text/html".Equals(alternateView.ContentType.MediaType, StringComparison.OrdinalIgnoreCase))
{
var stream = alternateView.ContentStream;
var buf = new byte[stream.Length];
stream.Read(buf, 0, buf.Length);
stream.Seek(0, SeekOrigin.Begin);//NOTE:seek to begin to keep HTML body
body.Html = new Content(Encoding.UTF8.GetString(buf)) { Charset = Encoding.UTF8.WebName };
break;
}
}
}
var message = new Message(new Content(mailMessage.Subject), body);
var seRequest = new SendEmailRequest(mailMessage.From.ToEncodedStringEx(), destination, message);
if (mailMessage.ReplyTo != null)
seRequest.ReplyToAddresses.Add(mailMessage.ReplyTo.Address);
ThrottleIfNeeded();
var response = _emailService.SendEmail(seRequest);
_lastSend = DateTime.UtcNow;
return response != null ? SendStatus.Ok : SendStatus.Failed;
}
private void ThrottleIfNeeded()
{
//Check last send and throttle if needed
if (_sendWindow != TimeSpan.MinValue)
{
if (DateTime.UtcNow - _lastSend <= _sendWindow)
//Possible BUG: at high frequncies maybe bug with to little differences
{
//This means that time passed from last send is less then message per second
_log.DebugFormat("send rate doesn't fit in send window. sleeping for:{0}", _sendWindow);
Thread.Sleep(_sendWindow);
}
}
}
private void RefreshQuotaIfNeeded()
{
if (!IsRefreshNeeded()) return;
lock (SynchRoot)
{
if (IsRefreshNeeded())//Double check
{
_log.DebugFormat("refreshing qouta. interval: {0} Last refresh was at: {1}", RefreshTimeout,
_lastRefresh);
//Do quota refresh
_lastRefresh = DateTime.UtcNow.AddMinutes(1);
try
{
var quotaRequest = new GetSendQuotaRequest();
_quota = _emailService.GetSendQuota(quotaRequest).GetSendQuotaResult;
_sendWindow = TimeSpan.FromSeconds(1.0 / _quota.MaxSendRate);
_log.DebugFormat("quota: {0}/{1} at {2} mps. send window:{3}", _quota.SentLast24Hours,
_quota.Max24HourSend, _quota.MaxSendRate, _sendWindow);
}
catch (Exception e)
{
_log.Error("error refreshing quota", e);
}
}
}
}
private static bool IsRefreshNeeded()
{
return (DateTime.UtcNow - _lastRefresh) > RefreshTimeout || _quota == null;
}
}
}

View File

@ -23,99 +23,113 @@
*
*/
namespace ASC.Common.Security
{
public class AscRandom : Random
{
private int _inext;
private int _inextp;
private const int MBIG = int.MaxValue;
private const int MSEED = 161803398;
private const int MZ = 0;
private readonly int[] seeds;
namespace ASC.Common.Security;
public class AscRandom : Random
{
private const int Mbig = int.MaxValue;
private const int Mseed = 161803398;
private const int Mz = 0;
private int _inext;
private int _inextp;
private readonly int[] _seeds;
public AscRandom() : this(Environment.TickCount) { }
public AscRandom(int seed)
{
_seeds = new int[56];
var num4 = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
var num2 = 161803398 - num4;
_seeds[^1] = num2;
var num3 = 1;
for (var i = 1; i < _seeds.Length - 1; i++)
{
var index = 21 * i % (_seeds.Length - 1);
_seeds[index] = num3;
num3 = num2 - num3;
if (num3 < 0)
{
num3 += int.MaxValue;
}
num2 = _seeds[index];
}
for (var j = 1; j < 5; j++)
{
for (var k = 1; k < _seeds.Length; k++)
{
_seeds[k] -= _seeds[1 + ((k + 30) % (_seeds.Length - 1))];
if (_seeds[k] < 0)
{
_seeds[k] += int.MaxValue;
}
}
}
_inext = 0;
_inextp = 21;
}
public override int Next(int maxValue)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException(nameof(maxValue));
}
return (int)(InternalSample() * 4.6566128752457969E-10 * maxValue);
}
public override void NextBytes(byte[] buffer)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
for (var i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)(InternalSample() % (byte.MaxValue + 1));
}
}
private int InternalSample()
{
var inext = _inext;
var inextp = _inextp;
public AscRandom() : this(Environment.TickCount)
{
}
if (++inext >= _seeds.Length - 1)
{
inext = 1;
}
if (++inextp >= _seeds.Length - 1)
{
inextp = 1;
}
var num = _seeds[inext] - _seeds[inextp];
if (num == int.MaxValue)
{
num--;
}
if (num < 0)
{
num += int.MaxValue;
}
public AscRandom(int seed)
{
seeds = new int[56];
var num4 = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
var num2 = 161803398 - num4;
seeds[^1] = num2;
var num3 = 1;
for (var i = 1; i < seeds.Length - 1; i++)
{
var index = 21 * i % (seeds.Length - 1);
seeds[index] = num3;
num3 = num2 - num3;
if (num3 < 0)
{
num3 += int.MaxValue;
}
num2 = seeds[index];
}
for (var j = 1; j < 5; j++)
{
for (var k = 1; k < seeds.Length; k++)
{
seeds[k] -= seeds[1 + ((k + 30) % (seeds.Length - 1))];
if (seeds[k] < 0)
{
seeds[k] += int.MaxValue;
}
}
}
_inext = 0;
_inextp = 21;
}
_seeds[inext] = num;
_inext = inext;
_inextp = inextp;
public override int Next(int maxValue)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException(nameof(maxValue));
}
return (int)(InternalSample() * 4.6566128752457969E-10 * maxValue);
}
public override void NextBytes(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
for (var i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)(InternalSample() % (byte.MaxValue + 1));
}
}
private int InternalSample()
{
var inext = this._inext;
var inextp = this._inextp;
if (++inext >= seeds.Length - 1)
{
inext = 1;
}
if (++inextp >= seeds.Length - 1)
{
inextp = 1;
}
var num = seeds[inext] - seeds[inextp];
if (num == int.MaxValue)
{
num--;
}
if (num < 0)
{
num += int.MaxValue;
}
seeds[inext] = num;
this._inext = inext;
this._inextp = inextp;
return num;
}
}
return num;
}
}

View File

@ -23,56 +23,40 @@
*
*/
namespace ASC.Common.Security.Authentication
namespace ASC.Common.Security.Authentication;
[Serializable]
public class Account : IAccount
{
[Serializable]
public class Account : IAccount
public Guid ID { get; private set; }
public string Name { get; private set; }
public virtual bool IsAuthenticated { get; private set; }
public string AuthenticationType => "ASC";
public Account(Guid id, string name, bool authenticated)
{
public Account(Guid id, string name, bool authenticated)
{
ID = id;
Name = name;
IsAuthenticated = authenticated;
}
#region IAccount Members
public Guid ID { get; private set; }
public string Name { get; private set; }
public object Clone()
{
return MemberwiseClone();
}
public string AuthenticationType
{
get { return "ASC"; }
}
public virtual bool IsAuthenticated
{
get;
private set;
}
#endregion
public override bool Equals(object obj)
{
return obj is IAccount a && ID.Equals(a.ID);
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override string ToString()
{
return Name;
}
ID = id;
Name = name;
IsAuthenticated = authenticated;
}
}
public object Clone()
{
return MemberwiseClone();
}
public override bool Equals(object obj)
{
return obj is IAccount a && ID.Equals(a.ID);
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override string ToString()
{
return Name;
}
}

View File

@ -23,10 +23,6 @@
*
*/
namespace ASC.Common.Security.Authentication
{
public interface IAccount : ISubject, ICloneable
{
}
}
namespace ASC.Common.Security.Authentication;
public interface IAccount : ISubject, ICloneable { }

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security.Authentication
{
public interface ISystemAccount : IAccount
{
}
}
namespace ASC.Common.Security.Authentication;
public interface ISystemAccount : IAccount { }

View File

@ -24,16 +24,13 @@
*/
namespace ASC.Common.Security.Authentication
namespace ASC.Common.Security.Authentication;
public interface IUserAccount : IAccount
{
public interface IUserAccount : IAccount
{
string Email { get; }
string FirstName { get; }
string LastName { get; }
string Title { get; }
int Tenant { get; }
}
}
string Email { get; }
string FirstName { get; }
string LastName { get; }
string Title { get; }
int Tenant { get; }
}

View File

@ -23,14 +23,11 @@
*
*/
namespace ASC.Common.Security.Authentication
namespace ASC.Common.Security.Authentication;
[Serializable]
public class SystemAccount : Account, ISystemAccount
{
[Serializable]
public class SystemAccount : Account, ISystemAccount
{
public SystemAccount(Guid id, string name, bool authenticated)
: base(id, name, authenticated)
{
}
}
}
public SystemAccount(Guid id, string name, bool authenticated)
: base(id, name, authenticated) { }
}

View File

@ -24,99 +24,111 @@
*/
#region usings
namespace ASC.Common.Security.Authorizing;
using System.Runtime.Serialization;
using System.Text;
#endregion
namespace ASC.Common.Security.Authorizing
[Serializable]
public class AuthorizingException : Exception
{
[Serializable]
public class AuthorizingException : Exception
public ISubject Subject { get; internal set; }
public IAction[] Actions { get; internal set; }
public override string Message => _message;
private readonly string _message;
public AuthorizingException(string message)
: base(message) { }
public AuthorizingException(ISubject subject, IAction[] actions)
{
private readonly string _Message;
public AuthorizingException(string message)
: base(message)
if (actions == null || actions.Length == 0)
{
throw new ArgumentNullException(nameof(actions));
}
public AuthorizingException(ISubject subject, IAction[] actions)
{
if (actions == null || actions.Length == 0) throw new ArgumentNullException(nameof(actions));
Subject = subject ?? throw new ArgumentNullException(nameof(subject));
Actions = actions;
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
_Message = string.Format(
"\"{0}\" access denied \"{1}\"",
subject,
sactions
);
}
Subject = subject ?? throw new ArgumentNullException(nameof(subject));
Actions = actions;
var sactions = "";
public AuthorizingException(ISubject subject, IAction[] actions, ISubject[] denySubjects, IAction[] denyActions)
{
_Message = FormatErrorMessage(subject, actions, denySubjects, denyActions);
}
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
protected AuthorizingException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
_Message = info.GetValue("_Message", typeof(string)) as string;
Subject = info.GetValue("Subject", typeof(ISubject)) as ISubject;
Actions = info.GetValue("Actions", typeof(IAction[])) as IAction[];
}
public override string Message
{
get { return _Message; }
}
public ISubject Subject { get; internal set; }
public IAction[] Actions { get; internal set; }
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Subject", Subject, typeof(ISubject));
info.AddValue("_Message", _Message, typeof(string));
info.AddValue("Actions", Actions, typeof(IAction[]));
base.GetObjectData(info, context);
}
internal static string FormatErrorMessage(ISubject subject, IAction[] actions, ISubject[] denySubjects,
IAction[] denyActions)
{
if (subject == null) throw new ArgumentNullException(nameof(subject));
if (actions == null || actions.Length == 0) throw new ArgumentNullException(nameof(actions));
if (denySubjects == null || denySubjects.Length == 0) throw new ArgumentNullException(nameof(denySubjects));
if (denyActions == null || denyActions.Length == 0) throw new ArgumentNullException(nameof(denyActions));
if (actions.Length != denySubjects.Length || actions.Length != denyActions.Length)
throw new ArgumentException();
var sb = new StringBuilder();
for (var i = 0; i < actions.Length; i++)
{
var action = actions[i];
var denyAction = denyActions[i];
var denySubject = denySubjects[i];
string reason;
if (denySubject != null && denyAction != null)
reason = $"{action.Name}:{(denySubject is IRole ? "role:" : "") + denySubject.Name} access denied {denyAction.Name}.";
else
reason = $"{action.Name}: access denied.";
if (i != actions.Length - 1)
reason += ", ";
sb.Append(reason);
}
var reasons = sb.ToString();
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
var message = $"\"{(subject is IRole ? "role:" : "") + subject.Name}\" access denied \"{sactions}\". Cause: {reasons}.";
return message;
}
_message = string.Format(
"\"{0}\" access denied \"{1}\"",
subject,
sactions
);
}
}
public AuthorizingException(ISubject subject, IAction[] actions, ISubject[] denySubjects, IAction[] denyActions) =>
_message = FormatErrorMessage(subject, actions, denySubjects, denyActions);
protected AuthorizingException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
_message = info.GetValue("_Message", typeof(string)) as string;
Subject = info.GetValue("Subject", typeof(ISubject)) as ISubject;
Actions = info.GetValue("Actions", typeof(IAction[])) as IAction[];
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Subject", Subject, typeof(ISubject));
info.AddValue("_Message", _message, typeof(string));
info.AddValue("Actions", Actions, typeof(IAction[]));
base.GetObjectData(info, context);
}
internal static string FormatErrorMessage(ISubject subject, IAction[] actions, ISubject[] denySubjects,
IAction[] denyActions)
{
if (subject == null)
{
throw new ArgumentNullException(nameof(subject));
}
if (actions == null || actions.Length == 0)
{
throw new ArgumentNullException(nameof(actions));
}
if (denySubjects == null || denySubjects.Length == 0)
{
throw new ArgumentNullException(nameof(denySubjects));
}
if (denyActions == null || denyActions.Length == 0)
{
throw new ArgumentNullException(nameof(denyActions));
}
if (actions.Length != denySubjects.Length || actions.Length != denyActions.Length)
{
throw new ArgumentException();
}
var sb = new StringBuilder();
for (var i = 0; i < actions.Length; i++)
{
var action = actions[i];
var denyAction = denyActions[i];
var denySubject = denySubjects[i];
string reason;
if (denySubject != null && denyAction != null)
{
reason = $"{action.Name}:{(denySubject is IRole ? "role:" : "") + denySubject.Name} access denied {denyAction.Name}.";
}
else
{
reason = $"{action.Name}: access denied.";
}
if (i != actions.Length - 1)
{
reason += ", ";
}
sb.Append(reason);
}
var reasons = sb.ToString();
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
var message = $"\"{(subject is IRole ? "role:" : "") + subject.Name}\" access denied \"{sactions}\". Cause: {reasons}.";
return message;
}
}

View File

@ -24,16 +24,19 @@
*/
namespace ASC.Common.Security.Authorizing
{
public static class AzObjectIdHelper
{
private static readonly string separator = "|";
namespace ASC.Common.Security.Authorizing;
public static string GetFullObjectId(ISecurityObjectId objectId)
public static class AzObjectIdHelper
{
private static readonly string _separator = "|";
public static string GetFullObjectId(ISecurityObjectId objectId)
{
if (objectId == null)
{
if (objectId == null) return null;
return string.Format("{0}{1}{2}", objectId.ObjectType.FullName, separator, objectId.SecurityId);
return null;
}
return $"{objectId.ObjectType.FullName}{_separator}{objectId.SecurityId}";
}
}
}

View File

@ -23,61 +23,67 @@
*
*/
namespace ASC.Common.Security.Authorizing;
#region usings
#endregion
namespace ASC.Common.Security.Authorizing
public class AzObjectSecurityProviderHelper
{
public class AzObjectSecurityProviderHelper
public ISecurityObjectId CurrentObjectId { get; private set; }
public bool ObjectRolesSupported => _currSecObjProvider != null && _currSecObjProvider.ObjectRolesSupported;
private readonly SecurityCallContext _callContext;
private readonly bool _currObjIdAsProvider;
private ISecurityObjectProvider _currSecObjProvider;
public AzObjectSecurityProviderHelper(ISecurityObjectId objectId, ISecurityObjectProvider secObjProvider)
{
private readonly SecurityCallContext callContext;
private readonly bool currObjIdAsProvider;
private ISecurityObjectProvider currSecObjProvider;
_currObjIdAsProvider = false;
CurrentObjectId = objectId ?? throw new ArgumentNullException(nameof(objectId));
_currSecObjProvider = secObjProvider;
public AzObjectSecurityProviderHelper(ISecurityObjectId objectId, ISecurityObjectProvider secObjProvider)
if (_currSecObjProvider == null && CurrentObjectId is ISecurityObjectProvider securityObjectProvider)
{
currObjIdAsProvider = false;
CurrentObjectId = objectId ?? throw new ArgumentNullException(nameof(objectId));
currSecObjProvider = secObjProvider;
if (currSecObjProvider == null && CurrentObjectId is ISecurityObjectProvider securityObjectProvider)
_currObjIdAsProvider = true;
_currSecObjProvider = securityObjectProvider;
}
_callContext = new SecurityCallContext();
}
public IEnumerable<IRole> GetObjectRoles(ISubject account)
{
var roles = _currSecObjProvider.GetObjectRoles(account, CurrentObjectId, _callContext);
foreach (var role in roles)
{
if (!_callContext.RolesList.Contains(role))
{
currObjIdAsProvider = true;
currSecObjProvider = securityObjectProvider;
_callContext.RolesList.Add(role);
}
callContext = new SecurityCallContext();
}
public ISecurityObjectId CurrentObjectId { get; private set; }
return roles;
}
public bool ObjectRolesSupported
public bool NextInherit()
{
if (_currSecObjProvider == null || !_currSecObjProvider.InheritSupported)
{
get { return currSecObjProvider != null && currSecObjProvider.ObjectRolesSupported; }
return false;
}
public IEnumerable<IRole> GetObjectRoles(ISubject account)
CurrentObjectId = _currSecObjProvider.InheritFrom(CurrentObjectId);
if (CurrentObjectId == null)
{
var roles = currSecObjProvider.GetObjectRoles(account, CurrentObjectId, callContext);
foreach (var role in roles)
{
if (!callContext.RolesList.Contains(role)) callContext.RolesList.Add(role);
}
return roles;
return false;
}
public bool NextInherit()
if (_currObjIdAsProvider)
{
if (currSecObjProvider == null || !currSecObjProvider.InheritSupported) return false;
CurrentObjectId = currSecObjProvider.InheritFrom(CurrentObjectId);
if (CurrentObjectId == null) return false;
if (currObjIdAsProvider)
{
currSecObjProvider = CurrentObjectId as ISecurityObjectProvider;
}
callContext.ObjectsStack.Insert(0, CurrentObjectId);
return currSecObjProvider != null;
_currSecObjProvider = CurrentObjectId as ISecurityObjectProvider;
}
_callContext.ObjectsStack.Insert(0, CurrentObjectId);
return _currSecObjProvider != null;
}
}

View File

@ -23,24 +23,23 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public static class Constants
{
public static class Constants
{
public static readonly Role Admin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "Admin");
public static readonly Role Admin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "Admin");
public static readonly Role Everyone = new Role(new Guid("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), "Everyone");
public static readonly Role Everyone = new Role(new Guid("c5cc67d1-c3e8-43c0-a3ad-3928ae3e5b5e"), "Everyone");
public static readonly Role User = new Role(new Guid("abef62db-11a8-4673-9d32-ef1d8af19dc0"), "User");
public static readonly Role User = new Role(new Guid("abef62db-11a8-4673-9d32-ef1d8af19dc0"), "User");
public static readonly Role Visitor = new Role(new Guid("aced04fa-dd96-4b35-af3e-346bf1eb972d"), "Visitor");
public static readonly Role Visitor = new Role(new Guid("aced04fa-dd96-4b35-af3e-346bf1eb972d"), "Visitor");
public static readonly Role Member = new Role(new Guid("ba74ca02-873f-43dc-8470-8620c156bc67"), "Member");
public static readonly Role Member = new Role(new Guid("ba74ca02-873f-43dc-8470-8620c156bc67"), "Member");
public static readonly Role Owner = new Role(new Guid("bba32183-a14d-48ed-9d39-c6b4d8925fbf"), "Owner");
public static readonly Role Owner = new Role(new Guid("bba32183-a14d-48ed-9d39-c6b4d8925fbf"), "Owner");
public static readonly Role Self = new Role(new Guid("5d5b7260-f7f7-49f1-a1c9-95fbb6a12604"), "Self");
}
}
public static readonly Role Self = new Role(new Guid("5d5b7260-f7f7-49f1-a1c9-95fbb6a12604"), "Self");
}

View File

@ -23,20 +23,17 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
[Serializable]
public class Ace
{
public Guid ActionId { get; set; }
public AceType Reaction { get; set; }
namespace ASC.Common.Security.Authorizing;
[Serializable]
public class Ace
{
public Guid ActionId { get; set; }
public AceType Reaction { get; set; }
public Ace(Guid actionId, AceType reaction)
{
ActionId = actionId;
Reaction = reaction;
}
}
}
public Ace(Guid actionId, AceType reaction)
{
ActionId = actionId;
Reaction = reaction;
}
}

View File

@ -24,11 +24,10 @@
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public enum AceType
{
public enum AceType
{
Allow,
Deny,
}
}
Allow,
Deny,
}

View File

@ -23,48 +23,44 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
[Serializable]
public class Action : IAction
{
[Serializable]
public class Action : IAction
public Guid ID { get; private set; }
public string Name { get; private set; }
public bool AdministratorAlwaysAllow { get; private set; }
public bool Conjunction { get; private set; }
public Action(Guid id, string name)
: this(id, name, true, true) { }
public Action(Guid id, string name, bool administratorAlwaysAllow, bool conjunction)
{
public Guid ID { get; private set; }
public string Name { get; private set; }
public bool AdministratorAlwaysAllow { get; private set; }
public bool Conjunction { get; private set; }
public Action(Guid id, string name)
: this(id, name, true, true)
if (id == Guid.Empty)
{
throw new ArgumentNullException(nameof(id));
}
public Action(Guid id, string name, bool administratorAlwaysAllow, bool conjunction)
{
if (id == Guid.Empty) throw new ArgumentNullException(nameof(id));
ID = id;
Name = name;
AdministratorAlwaysAllow = administratorAlwaysAllow;
Conjunction = conjunction;
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Action a && a.ID == ID;
}
public override string ToString()
{
return Name;
}
ID = id;
Name = name;
AdministratorAlwaysAllow = administratorAlwaysAllow;
Conjunction = conjunction;
}
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Action a && a.ID == ID;
}
public override string ToString()
{
return Name;
}
}

View File

@ -23,56 +23,50 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
[Serializable]
public sealed class Role : IRole
{
[Serializable]
public sealed class Role : IRole
public const string Everyone = "Everyone";
public const string Visitors = "Visitors";
public const string Users = "Users";
public const string Administrators = "Administrators";
public const string System = "System";
public Guid ID { get; internal set; }
public string Name { get; internal set; }
public string AuthenticationType => "ASC";
public bool IsAuthenticated => false;
public Role(Guid id, string name)
{
public const string Everyone = "Everyone";
public const string Visitors = "Visitors";
public const string Users = "Users";
public const string Administrators = "Administrators";
public const string System = "System";
public Guid ID { get; internal set; }
public string Name { get; internal set; }
public string AuthenticationType
if (id == Guid.Empty)
{
get { return "ASC"; }
throw new ArgumentException(nameof(id));
}
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
public bool IsAuthenticated
{
get { return false; }
}
public Role(Guid id, string name)
{
if (id == Guid.Empty) throw new ArgumentException("id");
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
ID = id;
Name = name;
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Role r && r.ID == ID;
}
public override string ToString()
{
return $"Role: {Name}";
}
ID = id;
Name = name;
}
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
public override bool Equals(object obj)
{
return obj is Role r && r.ID == ID;
}
public override string ToString()
{
return $"Role: {Name}";
}
}

View File

@ -23,16 +23,12 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public interface IAction
{
public interface IAction
{
Guid ID { get; }
string Name { get; }
bool AdministratorAlwaysAllow { get; }
bool Conjunction { get; }
}
}
Guid ID { get; }
string Name { get; }
bool AdministratorAlwaysAllow { get; }
bool Conjunction { get; }
}

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security.Authorizing
{
public interface IRole : ISubject
{
}
}
namespace ASC.Common.Security.Authorizing;
public interface IRole : ISubject { }

View File

@ -23,10 +23,9 @@
*
*/
namespace ASC.Common.Security.Authorizing
namespace ASC.Common.Security.Authorizing;
public interface ISubject : IIdentity
{
public interface ISubject : IIdentity
{
Guid ID { get; }
}
}
Guid ID { get; }
}

View File

@ -24,16 +24,12 @@
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
public enum HashAlg
{
public enum HashAlg
{
MD5,
SHA1,
SHA256,
SHA512
}
}
MD5,
SHA1,
SHA256,
SHA512
}

View File

@ -23,132 +23,146 @@
*
*/
namespace ASC.Security.Cryptography
{
public static class Hasher
{
private const HashAlg DefaultAlg = HashAlg.SHA256;
public static byte[] Hash(string data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(string data)
{
return Hash(data, DefaultAlg);
}
public static byte[] Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(byte[] data)
{
return Hash(data, DefaultAlg);
}
public static string Base64Hash(string data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(string data)
{
return Base64Hash(data, DefaultAlg);
}
public static string Base64Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(byte[] data)
{
return Base64Hash(data, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash, HashAlg hashAlg)
{
return string.Equals(
ComputeHash64(dataToCompare, hashAlg),
B2S64(hash)
);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
public static bool EqualHash(string dataToCompare, string hash, HashAlg hashAlg)
{
return EqualHash(S2B(dataToCompare), S642B(hash), hashAlg);
}
public static bool EqualHash(string dataToCompare, string hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
private static HashAlgorithm GetAlg(HashAlg hashAlg)
{
return hashAlg switch
{
HashAlg.MD5 => MD5.Create(),
HashAlg.SHA1 => SHA1.Create(),
HashAlg.SHA256 => SHA256.Create(),
HashAlg.SHA512 => SHA512.Create(),
_ => SHA256.Create()
};
}
private static byte[] S2B(string str)
{
if (str == null) throw new ArgumentNullException(nameof(str));
return Encoding.UTF8.GetBytes(str);
}
private static string B2S(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
return Encoding.UTF8.GetString(data);
}
private static byte[] S642B(string str)
{
if (str == null) throw new ArgumentNullException(nameof(str));
return Convert.FromBase64String(str);
}
private static string B2S64(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
return Convert.ToBase64String(data);
}
private static byte[] ComputeHash(byte[] data, HashAlg hashAlg)
namespace ASC.Security.Cryptography;
public static class Hasher
{
private const HashAlg DefaultAlg = HashAlg.SHA256;
public static byte[] Hash(string data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(string data)
{
return Hash(data, DefaultAlg);
}
public static byte[] Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
}
public static byte[] Hash(byte[] data)
{
return Hash(data, DefaultAlg);
}
public static string Base64Hash(string data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(string data)
{
return Base64Hash(data, DefaultAlg);
}
public static string Base64Hash(byte[] data, HashAlg hashAlg)
{
return ComputeHash64(data, hashAlg);
}
public static string Base64Hash(byte[] data)
{
return Base64Hash(data, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
public static bool EqualHash(string dataToCompare, string hash, HashAlg hashAlg)
{
return EqualHash(S2B(dataToCompare), S642B(hash), hashAlg);
}
public static bool EqualHash(string dataToCompare, string hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash, HashAlg hashAlg)
{
return string.Equals(
ComputeHash64(dataToCompare, hashAlg),
B2S64(hash)
);
}
private static HashAlgorithm GetAlg(HashAlg hashAlg)
{
return hashAlg switch
{
using var alg = GetAlg(hashAlg);
return alg.ComputeHash(data);
}
private static byte[] ComputeHash(string data, HashAlg hashAlg)
{
return ComputeHash(S2B(data), hashAlg);
}
private static string ComputeHash64(byte[] data, HashAlg hashAlg)
{
return B2S64(ComputeHash(data, hashAlg));
}
private static string ComputeHash64(string data, HashAlg hashAlg)
{
return ComputeHash64(S2B(data), hashAlg);
}
}
HashAlg.MD5 => MD5.Create(),
HashAlg.SHA1 => SHA1.Create(),
HashAlg.SHA256 => SHA256.Create(),
HashAlg.SHA512 => SHA512.Create(),
_ => SHA256.Create()
};
}
private static byte[] S2B(string str)
{
if (str == null)
{
throw new ArgumentNullException(nameof(str));
}
return Encoding.UTF8.GetBytes(str);
}
private static string B2S(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
return Encoding.UTF8.GetString(data);
}
private static byte[] S642B(string str)
{
if (str == null)
{
throw new ArgumentNullException(nameof(str));
}
return Convert.FromBase64String(str);
}
private static string B2S64(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
return Convert.ToBase64String(data);
}
private static byte[] ComputeHash(byte[] data, HashAlg hashAlg)
{
using var alg = GetAlg(hashAlg);
return alg.ComputeHash(data);
}
private static byte[] ComputeHash(string data, HashAlg hashAlg)
{
return ComputeHash(S2B(data), hashAlg);
}
private static string ComputeHash64(byte[] data, HashAlg hashAlg)
{
return B2S64(ComputeHash(data, hashAlg));
}
private static string ComputeHash64(string data, HashAlg hashAlg)
{
return ComputeHash64(S2B(data), hashAlg);
}
}

View File

@ -23,56 +23,54 @@
*
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
[Singletone]
public class InstanceCrypto
{
[Singletone]
public class InstanceCrypto
private readonly byte[] _eKey;
public InstanceCrypto(MachinePseudoKeys machinePseudoKeys)
{
private byte[] EKey { get; }
public InstanceCrypto(MachinePseudoKeys machinePseudoKeys)
{
EKey = machinePseudoKeys.GetMachineConstant(32);
}
public string Encrypt(string data)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(data)));
}
public byte[] Encrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = EKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var ms = new MemoryStream();
using var ss = new CryptoStream(ms, hasher.CreateEncryptor(), CryptoStreamMode.Write);
using var plainTextStream = new MemoryStream(data);
plainTextStream.CopyTo(ss);
ss.FlushFinalBlock();
hasher.Clear();
return ms.ToArray();
}
public string Decrypt(string data)
{
return Decrypt(Convert.FromBase64String(data));
}
public string Decrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = EKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var msDecrypt = new MemoryStream(data);
using var csDecrypt = new CryptoStream(msDecrypt, hasher.CreateDecryptor(), CryptoStreamMode.Read);
using var srDecrypt = new StreamReader(csDecrypt);
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
return srDecrypt.ReadToEnd();
}
_eKey = machinePseudoKeys.GetMachineConstant(32);
}
}
public string Encrypt(string data)
{
return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(data)));
}
public byte[] Encrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = _eKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var ms = new MemoryStream();
using var ss = new CryptoStream(ms, hasher.CreateEncryptor(), CryptoStreamMode.Write);
using var plainTextStream = new MemoryStream(data);
plainTextStream.CopyTo(ss);
ss.FlushFinalBlock();
hasher.Clear();
return ms.ToArray();
}
public string Decrypt(string data) => Decrypt(Convert.FromBase64String(data));
public string Decrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = _eKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var msDecrypt = new MemoryStream(data);
using var csDecrypt = new CryptoStream(msDecrypt, hasher.CreateDecryptor(), CryptoStreamMode.Read);
using var srDecrypt = new StreamReader(csDecrypt);
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
return srDecrypt.ReadToEnd();
}
}

View File

@ -23,47 +23,50 @@
*
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
[Singletone]
public class MachinePseudoKeys
{
[Singletone]
public class MachinePseudoKeys
private readonly byte[] _confKey = null;
public MachinePseudoKeys(IConfiguration configuration)
{
private readonly byte[] confkey = null;
var key = configuration["core:machinekey"];
public MachinePseudoKeys(IConfiguration configuration)
if (string.IsNullOrEmpty(key))
{
var key = configuration["core:machinekey"];
if (string.IsNullOrEmpty(key))
{
key = configuration["asc:common.machinekey"];
}
if (!string.IsNullOrEmpty(key))
{
confkey = Encoding.UTF8.GetBytes(key);
}
key = configuration["asc:common.machinekey"];
}
public byte[] GetMachineConstant()
if (!string.IsNullOrEmpty(key))
{
if (confkey != null)
{
return confkey;
}
var path = typeof(MachinePseudoKeys).Assembly.Location;
var fi = new FileInfo(path);
return BitConverter.GetBytes(fi.CreationTime.ToOADate());
}
public byte[] GetMachineConstant(int bytesCount)
{
var cnst = Enumerable.Repeat<byte>(0, sizeof(int)).Concat(GetMachineConstant()).ToArray();
var icnst = BitConverter.ToInt32(cnst, cnst.Length - sizeof(int));
var rnd = new AscRandom(icnst);
var buff = new byte[bytesCount];
rnd.NextBytes(buff);
return buff;
_confKey = Encoding.UTF8.GetBytes(key);
}
}
}
public byte[] GetMachineConstant()
{
if (_confKey != null)
{
return _confKey;
}
var path = typeof(MachinePseudoKeys).Assembly.Location;
var fi = new FileInfo(path);
return BitConverter.GetBytes(fi.CreationTime.ToOADate());
}
public byte[] GetMachineConstant(int bytesCount)
{
var cnst = Enumerable.Repeat<byte>(0, sizeof(int)).Concat(GetMachineConstant()).ToArray();
var icnst = BitConverter.ToInt32(cnst, cnst.Length - sizeof(int));
var rnd = new AscRandom(icnst);
var buff = new byte[bytesCount];
rnd.NextBytes(buff);
return buff;
}
}

View File

@ -23,69 +23,64 @@
*
*/
namespace ASC.Security.Cryptography
namespace ASC.Security.Cryptography;
[Singletone]
public class PasswordHasher
{
[Singletone]
public class PasswordHasher
public int Size { get; private set; }
public int Iterations { get; private set; }
public string Salt { get; private set; }
public PasswordHasher(IConfiguration configuration, MachinePseudoKeys machinePseudoKeys)
{
public PasswordHasher(IConfiguration configuration, MachinePseudoKeys machinePseudoKeys)
if (!int.TryParse(configuration["core:password:size"], out var size))
{
if (!int.TryParse(configuration["core:password:size"], out var size)) size = 256;
Size = size;
if (!int.TryParse(configuration["core.password.iterations"], out var iterations)) iterations = 100000;
Iterations = iterations;
Salt = (configuration["core:password:salt"] ?? "").Trim();
if (string.IsNullOrEmpty(Salt))
{
var salt = Hasher.Hash("{9450BEF7-7D9F-4E4F-A18A-971D8681722D}", HashAlg.SHA256);
var PasswordHashSaltBytes = KeyDerivation.Pbkdf2(
Encoding.UTF8.GetString(machinePseudoKeys.GetMachineConstant()),
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
Salt = BitConverter.ToString(PasswordHashSaltBytes).Replace("-", string.Empty).ToLower();
}
size = 256;
}
public int Size
Size = size;
if (!int.TryParse(configuration["core.password.iterations"], out var iterations))
{
get;
private set;
iterations = 100000;
}
public int Iterations
Iterations = iterations;
Salt = (configuration["core:password:salt"] ?? "").Trim();
if (string.IsNullOrEmpty(Salt))
{
get;
private set;
}
var salt = Hasher.Hash("{9450BEF7-7D9F-4E4F-A18A-971D8681722D}", HashAlg.SHA256);
public string Salt
{
get;
private set;
}
public string GetClientPassword(string password)
{
if (string.IsNullOrWhiteSpace(password)) password = Guid.NewGuid().ToString();
var salt = new UTF8Encoding(false).GetBytes(Salt);
var hashBytes = KeyDerivation.Pbkdf2(
password,
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
var hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty).ToLower();
return hash;
var PasswordHashSaltBytes = KeyDerivation.Pbkdf2(
Encoding.UTF8.GetString(machinePseudoKeys.GetMachineConstant()),
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
Salt = BitConverter.ToString(PasswordHashSaltBytes).Replace("-", string.Empty).ToLower();
}
}
public string GetClientPassword(string password)
{
if (string.IsNullOrWhiteSpace(password))
{
password = Guid.NewGuid().ToString();
}
var salt = new UTF8Encoding(false).GetBytes(Salt);
var hashBytes = KeyDerivation.Pbkdf2(
password,
salt,
KeyDerivationPrf.HMACSHA256,
Iterations,
Size / 8);
var hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty).ToLower();
return hash;
}
}

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security
{
public interface ISecurityObject : ISecurityObjectId, ISecurityObjectProvider
{
}
}
namespace ASC.Common.Security;
public interface ISecurityObject : ISecurityObjectId, ISecurityObjectProvider { }

View File

@ -24,11 +24,10 @@
*/
namespace ASC.Common.Security
namespace ASC.Common.Security;
public interface ISecurityObjectId
{
public interface ISecurityObjectId
{
object SecurityId { get; }
Type ObjectType { get; }
}
}
object SecurityId { get; }
Type ObjectType { get; }
}

View File

@ -24,15 +24,13 @@
*/
namespace ASC.Common.Security
{
public interface ISecurityObjectProvider
{
bool InheritSupported { get; }
bool ObjectRolesSupported { get; }
ISecurityObjectId InheritFrom(ISecurityObjectId objectId);
IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext);
}
}
namespace ASC.Common.Security;
public interface ISecurityObjectProvider
{
bool InheritSupported { get; }
bool ObjectRolesSupported { get; }
ISecurityObjectId InheritFrom(ISecurityObjectId objectId);
IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext);
}

View File

@ -23,20 +23,17 @@
*
*/
namespace ASC.Common.Security
{
public class SecurityCallContext
{
public SecurityCallContext()
{
ObjectsStack = new List<ISecurityObjectId>();
RolesList = new List<IRole>();
}
public List<ISecurityObjectId> ObjectsStack { get; private set; }
public List<IRole> RolesList { get; private set; }
public object UserData { get; set; }
}
}
namespace ASC.Common.Security;
public class SecurityCallContext
{
public object UserData { get; set; }
public List<ISecurityObjectId> ObjectsStack { get; private set; }
public List<IRole> RolesList { get; private set; }
public SecurityCallContext()
{
ObjectsStack = new List<ISecurityObjectId>();
RolesList = new List<IRole>();
}
}

View File

@ -23,31 +23,28 @@
*
*/
namespace ASC.Common.Security
{
[DebuggerDisplay("ObjectType: {ObjectType.Name}, SecurityId: {SecurityId}")]
public class SecurityObjectId : ISecurityObjectId
{
public object SecurityId { get; private set; }
public Type ObjectType { get; private set; }
public SecurityObjectId(object id, Type objType)
{
SecurityId = id;
ObjectType = objType ?? throw new ArgumentNullException(nameof(objType));
}
public override int GetHashCode()
{
return AzObjectIdHelper.GetFullObjectId(this).GetHashCode();
}
public override bool Equals(object obj)
{
return obj is SecurityObjectId other &&
Equals(AzObjectIdHelper.GetFullObjectId(other), AzObjectIdHelper.GetFullObjectId(this));
}
}
namespace ASC.Common.Security;
[DebuggerDisplay("ObjectType: {ObjectType.Name}, SecurityId: {SecurityId}")]
public class SecurityObjectId : ISecurityObjectId
{
public object SecurityId { get; private set; }
public Type ObjectType { get; private set; }
public SecurityObjectId(object id, Type objType)
{
SecurityId = id;
ObjectType = objType ?? throw new ArgumentNullException(nameof(objType));
}
public override int GetHashCode()
{
return AzObjectIdHelper.GetFullObjectId(this).GetHashCode();
}
public override bool Equals(object obj)
{
return obj is SecurityObjectId other &&
Equals(AzObjectIdHelper.GetFullObjectId(other), AzObjectIdHelper.GetFullObjectId(this));
}
}

View File

@ -25,110 +25,84 @@
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace ASC.Common.Threading
{
public class DistributedTask
{
public Action<DistributedTask> Publication { get; set; }
namespace ASC.Common.Threading;
protected internal DistributedTaskCache DistributedTaskCache { get; internal set; }
public int InstanceId
public class DistributedTask
{
public Action<DistributedTask> Publication { get; set; }
public int InstanceId
{
get => DistributedTaskCache.InstanceId;
set => DistributedTaskCache.InstanceId = value;
}
public string Id
{
get => DistributedTaskCache.Id;
protected set => DistributedTaskCache.Id = value ?? "";
}
public DistributedTaskStatus Status
{
get => Enum.Parse<DistributedTaskStatus>(DistributedTaskCache.Status);
set => DistributedTaskCache.Status = value.ToString();
}
public Exception Exception
{
get => new Exception(DistributedTaskCache.Exception);
set => DistributedTaskCache.Exception = value?.ToString() ?? "";
}
protected internal DistributedTaskCache DistributedTaskCache { get; internal set; }
public DistributedTask()
{
DistributedTaskCache = new DistributedTaskCache
{
get
{
return DistributedTaskCache.InstanceId;
}
set
{
DistributedTaskCache.InstanceId = value;
}
}
public string Id
Id = Guid.NewGuid().ToString()
};
}
public DistributedTask(DistributedTaskCache distributedTaskCache)
{
DistributedTaskCache = distributedTaskCache;
}
public T GetProperty<T>(string name)
{
var prop = DistributedTaskCache.Props.FirstOrDefault(r => r.Key == name);
if (prop == null)
{
get
{
return DistributedTaskCache.Id;
}
protected set
{
DistributedTaskCache.Id = value ?? "";
}
}
public DistributedTaskStatus Status
{
get
{
return Enum.Parse<DistributedTaskStatus>(DistributedTaskCache.Status);
}
set
{
DistributedTaskCache.Status = value.ToString();
}
}
public Exception Exception
{
get
{
return new Exception(DistributedTaskCache.Exception);
}
set
{
DistributedTaskCache.Exception = value?.ToString() ?? "";
}
return default;
}
public DistributedTask()
{
DistributedTaskCache = new DistributedTaskCache
{
Id = Guid.NewGuid().ToString()
};
}
public DistributedTask(DistributedTaskCache distributedTaskCache)
{
DistributedTaskCache = distributedTaskCache;
}
public T GetProperty<T>(string name)
{
var prop = DistributedTaskCache.Props.FirstOrDefault(r => r.Key == name);
if (prop == null) return default;
return JsonSerializer.Deserialize<T>(prop.Value);
}
public void SetProperty(string name, object value)
{
var prop = new DistributedTaskCache.Types.DistributedTaskCacheProp()
{
Key = name,
Value = JsonSerializer.Serialize(value)
};
return JsonSerializer.Deserialize<T>(prop.Value);
}
var current = DistributedTaskCache.Props.SingleOrDefault(r => r.Key == name);
if (current != null)
{
DistributedTaskCache.Props.Remove(current);
}
if (value != null)
{
DistributedTaskCache.Props.Add(prop);
}
}
public void PublishChanges()
{
if (Publication == null)
{
throw new InvalidOperationException("Publication not found.");
}
Publication(this);
}
}
}
public void SetProperty(string name, object value)
{
var prop = new DistributedTaskCache.Types.DistributedTaskCacheProp()
{
Key = name,
Value = JsonSerializer.Serialize(value)
};
var current = DistributedTaskCache.Props.SingleOrDefault(r => r.Key == name);
if (current != null)
{
DistributedTaskCache.Props.Remove(current);
}
if (value != null)
{
DistributedTaskCache.Props.Add(prop);
}
}
public void PublishChanges()
{
if (Publication == null)
{
throw new InvalidOperationException("Publication not found.");
}
Publication(this);
}
}

View File

@ -1,64 +1,41 @@
namespace ASC.Common.Threading
namespace ASC.Common.Threading;
[Transient]
public class DistributedTaskProgress : DistributedTask
{
[Transient]
public class DistributedTaskProgress : DistributedTask
public double Percentage
{
public double Percentage
{
get
{
return Math.Min(100.0, Math.Max(0, DistributedTaskCache.Percentage));
}
set
{
DistributedTaskCache.Percentage = value;
}
}
public bool IsCompleted
{
get
{
return DistributedTaskCache.IsCompleted;
}
set
{
DistributedTaskCache.IsCompleted = value;
}
}
protected int StepCount
{
get
{
return DistributedTaskCache.StepCount;
}
set
{
DistributedTaskCache.StepCount = value;
}
}
protected void StepDone()
{
if (StepCount > 0)
{
Percentage += 100.0 / StepCount;
}
PublishChanges();
}
public void RunJob()
{
Percentage = 0;
Status = DistributedTaskStatus.Running;
DoJob();
}
protected virtual void DoJob()
{
}
get => Math.Min(100.0, Math.Max(0, DistributedTaskCache.Percentage));
set => DistributedTaskCache.Percentage = value;
}
}
public bool IsCompleted
{
get => DistributedTaskCache.IsCompleted;
set => DistributedTaskCache.IsCompleted = value;
}
protected int StepCount
{
get => DistributedTaskCache.StepCount;
set => DistributedTaskCache.StepCount = value;
}
public void RunJob()
{
Percentage = 0;
Status = DistributedTaskStatus.Running;
DoJob();
}
protected virtual void DoJob() { }
protected void StepDone()
{
if (StepCount > 0)
{
Percentage += 100.0 / StepCount;
}
PublishChanges();
}
}

View File

@ -23,301 +23,318 @@
*
*/
namespace ASC.Common.Threading
namespace ASC.Common.Threading;
[Singletone]
public class DistributedTaskCacheNotify
{
[Singletone]
public class DistributedTaskCacheNotify
public ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get; }
public ICache Cache { get; }
private readonly ICacheNotify<DistributedTaskCancelation> _cancelTaskNotify;
private readonly ICacheNotify<DistributedTaskCache> _taskCacheNotify;
public DistributedTaskCacheNotify(
ICacheNotify<DistributedTaskCancelation> cancelTaskNotify,
ICacheNotify<DistributedTaskCache> taskCacheNotify,
ICache cache)
{
public ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get; }
public ICache Cache { get; }
private readonly ICacheNotify<DistributedTaskCancelation> notify;
private readonly ICacheNotify<DistributedTaskCache> notifyCache;
Cancelations = new ConcurrentDictionary<string, CancellationTokenSource>();
public DistributedTaskCacheNotify(
ICacheNotify<DistributedTaskCancelation> notify,
ICacheNotify<DistributedTaskCache> notifyCache,
ICache cache)
Cache = cache;
_cancelTaskNotify = cancelTaskNotify;
cancelTaskNotify.Subscribe((c) =>
{
Cancelations = new ConcurrentDictionary<string, CancellationTokenSource>();
Cache = cache;
this.notify = notify;
notify.Subscribe((c) =>
{
if (Cancelations.TryGetValue(c.Id, out var s))
{
s.Cancel();
}
}, CacheNotifyAction.Remove);
this.notifyCache = notifyCache;
notifyCache.Subscribe((c) =>
if (Cancelations.TryGetValue(c.Id, out var s))
{
Cache.HashSet(c.Key, c.Id, (DistributedTaskCache)null);
}, CacheNotifyAction.Remove);
s.Cancel();
}
}, CacheNotifyAction.Remove);
notifyCache.Subscribe((c) =>
{
Cache.HashSet(c.Key, c.Id, c);
}, CacheNotifyAction.InsertOrUpdate);
}
_taskCacheNotify = taskCacheNotify;
public void CancelTask(string id)
{
notify.Publish(new DistributedTaskCancelation() { Id = id }, CacheNotifyAction.Remove);
}
public void SetTask(DistributedTask task)
taskCacheNotify.Subscribe((c) =>
{
notifyCache.Publish(task.DistributedTaskCache, CacheNotifyAction.InsertOrUpdate);
}
public void RemoveTask(string id, string key)
Cache.HashSet(c.Key, c.Id, (DistributedTaskCache)null);
}, CacheNotifyAction.Remove);
taskCacheNotify.Subscribe((c) =>
{
notifyCache.Publish(new DistributedTaskCache() { Id = id, Key = key }, CacheNotifyAction.Remove);
}
Cache.HashSet(c.Key, c.Id, c);
}, CacheNotifyAction.InsertOrUpdate);
}
[Singletone(typeof(ConfigureDistributedTaskQueue))]
public class DistributedTaskQueueOptionsManager : OptionsManager<DistributedTaskQueue>
{
public DistributedTaskQueueOptionsManager(IOptionsFactory<DistributedTaskQueue> factory) : base(factory)
{
}
public void CancelTask(string id)
{
_cancelTaskNotify.Publish(new DistributedTaskCancelation() { Id = id }, CacheNotifyAction.Remove);
}
public DistributedTaskQueue Get<T>() where T : DistributedTask
{
return Get(typeof(T).FullName);
}
public void SetTask(DistributedTask task)
{
_taskCacheNotify.Publish(task.DistributedTaskCache, CacheNotifyAction.InsertOrUpdate);
}
public void RemoveTask(string id, string key)
{
_taskCacheNotify.Publish(new DistributedTaskCache() { Id = id, Key = key }, CacheNotifyAction.Remove);
}
}
[Singletone(typeof(ConfigureDistributedTaskQueue))]
public class DistributedTaskQueueOptionsManager : OptionsManager<DistributedTaskQueue>
{
public DistributedTaskQueueOptionsManager(IOptionsFactory<DistributedTaskQueue> factory) : base(factory) { }
public DistributedTaskQueue Get<T>() where T : DistributedTask
{
return Get(typeof(T).FullName);
}
}
[Scope]
public class ConfigureDistributedTaskQueue : IConfigureNamedOptions<DistributedTaskQueue>
{
private readonly DistributedTaskCacheNotify _distributedTaskCacheNotify;
public readonly IServiceProvider _serviceProvider;
public ConfigureDistributedTaskQueue(
DistributedTaskCacheNotify distributedTaskCacheNotify,
IServiceProvider serviceProvider)
{
_distributedTaskCacheNotify = distributedTaskCacheNotify;
_serviceProvider = serviceProvider;
}
public void Configure(DistributedTaskQueue queue)
{
queue.DistributedTaskCacheNotify = _distributedTaskCacheNotify;
queue.ServiceProvider = _serviceProvider;
}
public void Configure(string name, DistributedTaskQueue options)
{
Configure(options);
options.Name = name;
}
}
public class DistributedTaskQueue
{
public IServiceProvider ServiceProvider { get; set; }
public DistributedTaskCacheNotify DistributedTaskCacheNotify { get; set; }
public string Name
{
get => _name;
set => _name = value + GetType().Name;
}
public int MaxThreadsCount
{
set => Scheduler = value <= 0
? TaskScheduler.Default
: new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, value).ConcurrentScheduler;
}
[Scope]
public class ConfigureDistributedTaskQueue : IConfigureNamedOptions<DistributedTaskQueue>
private ICache Cache => DistributedTaskCacheNotify.Cache;
private TaskScheduler Scheduler { get; set; } = TaskScheduler.Default;
public static readonly int InstanceId = Process.GetCurrentProcess().Id;
private string _name;
private ConcurrentDictionary<string, CancellationTokenSource> Cancelations
{
private DistributedTaskCacheNotify DistributedTaskCacheNotify { get; }
public IServiceProvider ServiceProvider { get; }
public ConfigureDistributedTaskQueue(DistributedTaskCacheNotify distributedTaskCacheNotify, IServiceProvider serviceProvider)
get
{
DistributedTaskCacheNotify = distributedTaskCacheNotify;
ServiceProvider = serviceProvider;
}
public void Configure(DistributedTaskQueue queue)
{
queue.DistributedTaskCacheNotify = DistributedTaskCacheNotify;
queue.ServiceProvider = ServiceProvider;
}
public void Configure(string name, DistributedTaskQueue options)
{
Configure(options);
options.Name = name;
return DistributedTaskCacheNotify.Cancelations;
}
}
public class DistributedTaskQueue
{
public static readonly int InstanceId = Process.GetCurrentProcess().Id;
private string key;
private TaskScheduler Scheduler { get; set; } = TaskScheduler.Default;
public IServiceProvider ServiceProvider { get; set; }
public string Name { get { return key; } set { key = value + GetType().Name; } }
private ICache Cache { get => DistributedTaskCacheNotify.Cache; }
private ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get => DistributedTaskCacheNotify.Cancelations; }
public int MaxThreadsCount
{
set
{
Scheduler = value <= 0
? TaskScheduler.Default
: new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, value).ConcurrentScheduler;
}
}
public DistributedTaskCacheNotify DistributedTaskCacheNotify { get; set; }
public void QueueTask(DistributedTaskProgress taskProgress)
{
QueueTask((a, b) => taskProgress.RunJob(), taskProgress);
}
public void QueueTask(Action<DistributedTask, CancellationToken> action, DistributedTask distributedTask = null)
{
if (distributedTask == null)
{
distributedTask = new DistributedTask();
}
distributedTask.InstanceId = InstanceId;
var cancelation = new CancellationTokenSource();
var token = cancelation.Token;
Cancelations[distributedTask.Id] = cancelation;
var task = new Task(() => { action(distributedTask, token); }, token, TaskCreationOptions.LongRunning);
task
.ConfigureAwait(false)
.GetAwaiter()
.OnCompleted(() => OnCompleted(task, distributedTask.Id));
distributedTask.Status = DistributedTaskStatus.Running;
if (distributedTask.Publication == null)
{
distributedTask.Publication = GetPublication();
}
distributedTask.PublishChanges();
task.Start(Scheduler);
}
public IEnumerable<DistributedTask> GetTasks()
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(key).Values.Select(r => new DistributedTask(r)).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
t.Publication = GetPublication();
}
});
return tasks;
}
public IEnumerable<T> GetTasks<T>() where T : DistributedTask
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(key).Values.Select(r =>
{
var result = ServiceProvider.GetService<T>();
result.DistributedTaskCache = r;
return result;
}).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
t.Publication = GetPublication();
}
});
return tasks;
}
public T GetTask<T>(string id) where T : DistributedTask
{
var cache = Cache.HashGet<DistributedTaskCache>(key, id);
if (cache != null)
{
using var scope = ServiceProvider.CreateScope();
var task = scope.ServiceProvider.GetService<T>();
task.DistributedTaskCache = cache;
if (task.Publication == null)
{
task.Publication = GetPublication();
}
return task;
}
return null;
}
public DistributedTask GetTask(string id)
{
var cache = Cache.HashGet<DistributedTaskCache>(key, id);
if (cache != null)
{
var task = new DistributedTask();
task.DistributedTaskCache = cache;
if (task.Publication == null)
{
task.Publication = GetPublication();
}
return task;
}
return null;
}
public void SetTask(DistributedTask task)
{
DistributedTaskCacheNotify.SetTask(task);
}
public void RemoveTask(string id)
{
DistributedTaskCacheNotify.RemoveTask(id, key);
}
public void CancelTask(string id)
{
DistributedTaskCacheNotify.CancelTask(id);
}
private void OnCompleted(Task task, string id)
{
var distributedTask = GetTask(id);
if (distributedTask != null)
{
distributedTask.Status = DistributedTaskStatus.Completed;
distributedTask.Exception = task.Exception;
if (task.IsFaulted)
{
distributedTask.Status = DistributedTaskStatus.Failted;
}
if (task.IsCanceled)
{
distributedTask.Status = DistributedTaskStatus.Canceled;
}
Cancelations.TryRemove(id, out _);
distributedTask.PublishChanges();
}
}
private Action<DistributedTask> GetPublication()
{
return (t) =>
{
if (t.DistributedTaskCache != null)
{
t.DistributedTaskCache.Key = key;
}
DistributedTaskCacheNotify.SetTask(t);
};
}
public void QueueTask(DistributedTaskProgress taskProgress)
{
QueueTask((a, b) => taskProgress.RunJob(), taskProgress);
}
public static class DistributedTaskQueueExtention
{
public static DIHelper AddDistributedTaskQueueService<T>(this DIHelper services, int maxThreadsCount) where T : DistributedTask
public void QueueTask(Action<DistributedTask, CancellationToken> action, DistributedTask distributedTask = null)
{
if (distributedTask == null)
{
services.TryAdd<DistributedTaskCacheNotify>();
services.TryAdd<DistributedTaskQueueOptionsManager>();
services.TryAdd<DistributedTaskQueue>();
distributedTask = new DistributedTask();
}
var type = typeof(T);
if (!type.IsAbstract)
distributedTask.InstanceId = InstanceId;
var cancelation = new CancellationTokenSource();
var token = cancelation.Token;
Cancelations[distributedTask.Id] = cancelation;
var task = new Task(() => { action(distributedTask, token); }, token, TaskCreationOptions.LongRunning);
task.ConfigureAwait(false)
.GetAwaiter()
.OnCompleted(() => OnCompleted(task, distributedTask.Id));
distributedTask.Status = DistributedTaskStatus.Running;
if (distributedTask.Publication == null)
{
distributedTask.Publication = GetPublication();
}
distributedTask.PublishChanges();
task.Start(Scheduler);
}
public IEnumerable<DistributedTask> GetTasks()
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(_name).Values.Select(r => new DistributedTask(r)).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
services.TryAdd<T>();
t.Publication = GetPublication();
}
});
return tasks;
}
public IEnumerable<T> GetTasks<T>() where T : DistributedTask
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(_name).Values.Select(r =>
{
var result = ServiceProvider.GetService<T>();
result.DistributedTaskCache = r;
return result;
}).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
{
t.Publication = GetPublication();
}
});
return tasks;
}
public T GetTask<T>(string id) where T : DistributedTask
{
var cache = Cache.HashGet<DistributedTaskCache>(_name, id);
if (cache != null)
{
using var scope = ServiceProvider.CreateScope();
var task = scope.ServiceProvider.GetService<T>();
task.DistributedTaskCache = cache;
if (task.Publication == null)
{
task.Publication = GetPublication();
}
services.TryAddSingleton<IConfigureOptions<DistributedTaskQueue>, ConfigureDistributedTaskQueue>();
return task;
}
_ = services.Configure<DistributedTaskQueue>(type.Name, r =>
return null;
}
public DistributedTask GetTask(string id)
{
var cache = Cache.HashGet<DistributedTaskCache>(_name, id);
if (cache != null)
{
var task = new DistributedTask();
task.DistributedTaskCache = cache;
if (task.Publication == null)
{
r.MaxThreadsCount = maxThreadsCount;
task.Publication = GetPublication();
}
return task;
}
return null;
}
public void SetTask(DistributedTask task)
{
DistributedTaskCacheNotify.SetTask(task);
}
public void RemoveTask(string id)
{
DistributedTaskCacheNotify.RemoveTask(id, _name);
}
public void CancelTask(string id)
{
DistributedTaskCacheNotify.CancelTask(id);
}
private void OnCompleted(Task task, string id)
{
var distributedTask = GetTask(id);
if (distributedTask != null)
{
distributedTask.Status = DistributedTaskStatus.Completed;
distributedTask.Exception = task.Exception;
if (task.IsFaulted)
{
distributedTask.Status = DistributedTaskStatus.Failted;
}
if (task.IsCanceled)
{
distributedTask.Status = DistributedTaskStatus.Canceled;
}
Cancelations.TryRemove(id, out _);
distributedTask.PublishChanges();
}
}
private Action<DistributedTask> GetPublication()
{
return (t) =>
{
if (t.DistributedTaskCache != null)
{
t.DistributedTaskCache.Key = _name;
}
DistributedTaskCacheNotify.SetTask(t);
};
}
}
public static class DistributedTaskQueueExtention
{
public static DIHelper AddDistributedTaskQueueService<T>(this DIHelper services, int maxThreadsCount) where T : DistributedTask
{
services.TryAdd<DistributedTaskCacheNotify>();
services.TryAdd<DistributedTaskQueueOptionsManager>();
services.TryAdd<DistributedTaskQueue>();
var type = typeof(T);
if (!type.IsAbstract)
{
services.TryAdd<T>();
}
services.TryAddSingleton<IConfigureOptions<DistributedTaskQueue>, ConfigureDistributedTaskQueue>();
_ = services.Configure<DistributedTaskQueue>(type.Name, r =>
{
r.MaxThreadsCount = maxThreadsCount;
//r.errorCount = 1;
});
return services;
}
return services;
}
}
}

View File

@ -24,14 +24,13 @@
*/
namespace ASC.Common.Threading
namespace ASC.Common.Threading;
public enum DistributedTaskStatus
{
public enum DistributedTaskStatus
{
Created,
Running,
Completed,
Canceled,
Failted
}
Created,
Running,
Completed,
Canceled,
Failted
}

View File

@ -23,16 +23,15 @@
*
*/
namespace ASC.Common.Threading.Progress
{
public interface IProgressItem : ICloneable
{
string Id { get; }
DistributedTaskStatus Status { get; set; }
object Error { get; set; }
double Percentage { get; set; }
bool IsCompleted { get; set; }
namespace ASC.Common.Threading.Progress;
void RunJob();
}
}
public interface IProgressItem : ICloneable
{
string Id { get; }
DistributedTaskStatus Status { get; set; }
object Error { get; set; }
double Percentage { get; set; }
bool IsCompleted { get; set; }
void RunJob();
}

View File

@ -1,86 +1,82 @@
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public class ConnectionStringCollection : IEnumerable<ConnectionStringSettings>
{
public class ConnectionStringCollection : IEnumerable<ConnectionStringSettings>
private List<ConnectionStringSettings> _data;
public ConnectionStringSettings this[string name] => _data.FirstOrDefault(r => r.Name == name);
public ConnectionStringCollection(IEnumerable<ConnectionStringSettings> data)
{
private List<ConnectionStringSettings> Data { get; set; }
public ConnectionStringCollection(IEnumerable<ConnectionStringSettings> data) => Data = data.ToList();
public IEnumerator<ConnectionStringSettings> GetEnumerator()
{
return Data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public ConnectionStringSettings this[string name]
{
get
{
return Data.FirstOrDefault(r => r.Name == name);
}
}
_data = data.ToList();
}
[Singletone]
public class ConfigurationExtension
public IEnumerator<ConnectionStringSettings> GetEnumerator()
{
private IConfiguration Configuration { get; }
private Lazy<ConnectionStringCollection> ConnectionStringSettings { get; }
return _data.GetEnumerator();
}
public ConfigurationExtension(IConfiguration configuration)
{
Configuration = configuration;
ConnectionStringSettings = new Lazy<ConnectionStringCollection>(new ConnectionStringCollection(GetSettings<ConnectionStringSettings>("ConnectionStrings")));
}
public IEnumerable<T> GetSettings<T>(string section) where T : new()
{
var result = new List<T>();
var sectionSettings = Configuration.GetSection(section);
foreach (var ch in sectionSettings.GetChildren())
{
var cs = new T();
ch.Bind(cs);
result.Add(cs);
}
return result;
}
public T GetSetting<T>(string section) where T : new()
{
return GetSetting(section, new T());
}
public T GetSetting<T>(string section, T instance)
{
var sectionSettings = Configuration.GetSection(section);
sectionSettings.Bind(instance);
return instance;
}
public ConnectionStringCollection GetConnectionStrings()
{
return ConnectionStringSettings.Value;
}
public ConnectionStringSettings GetConnectionStrings(string key)
{
return GetConnectionStrings()[key];
}
public string this[string key]
{
get => Configuration[key];
set => Configuration[key] = value;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
[Singletone]
public class ConfigurationExtension
{
public string this[string key]
{
get => _configuration[key];
set => _configuration[key] = value;
}
private readonly IConfiguration _configuration;
private readonly Lazy<ConnectionStringCollection> _connectionStringSettings;
public ConfigurationExtension(IConfiguration configuration)
{
_configuration = configuration;
_connectionStringSettings = new Lazy<ConnectionStringCollection>(new ConnectionStringCollection(GetSettings<ConnectionStringSettings>("ConnectionStrings")));
}
public IEnumerable<T> GetSettings<T>(string section) where T : new()
{
var result = new List<T>();
var sectionSettings = _configuration.GetSection(section);
foreach (var ch in sectionSettings.GetChildren())
{
var cs = new T();
ch.Bind(cs);
result.Add(cs);
}
return result;
}
public T GetSetting<T>(string section) where T : new()
{
return GetSetting(section, new T());
}
public T GetSetting<T>(string section, T instance)
{
var sectionSettings = _configuration.GetSection(section);
sectionSettings.Bind(instance);
return instance;
}
public ConnectionStringCollection GetConnectionStrings()
{
return _connectionStringSettings.Value;
}
public ConnectionStringSettings GetConnectionStrings(string key)
{
return GetConnectionStrings()[key];
}
}

View File

@ -23,28 +23,29 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class CrossPlatform
{
public static class CrossPlatform
private static char[] _pathSplitCharacters = new char[] { '/', '\\' };
public static string PathCombine(string basePath, params string[] additional)
{
public static string PathCombine(string basePath, params string[] additional)
var splits = additional.Select(s => s.Split(_pathSplitCharacters)).ToArray();
var totalLength = splits.Sum(arr => arr.Length);
var segments = new string[totalLength + 1];
segments[0] = basePath;
var i = 0;
foreach (var split in splits)
{
var splits = additional.Select(s => s.Split(pathSplitCharacters)).ToArray();
var totalLength = splits.Sum(arr => arr.Length);
var segments = new string[totalLength + 1];
segments[0] = basePath;
var i = 0;
foreach (var split in splits)
foreach (var value in split)
{
foreach (var value in split)
{
i++;
segments[i] = value;
}
i++;
segments[i] = value;
}
return Path.Combine(segments);
}
static char[] pathSplitCharacters = new char[] { '/', '\\' };
return Path.Combine(segments);
}
}

View File

@ -23,228 +23,247 @@
*
*/
namespace ASC.Common.Utils
{
public class DnsLookup
{
private readonly IDnsResolver _sDnsResolver;
private readonly DnsClient _dnsClient;
public DnsLookup()
{
_dnsClient = DnsClient.Default;
_sDnsResolver = new DnsStubResolver(_dnsClient);
}
/// <summary>
/// Get domain MX records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of MxRecord</returns>
public List<MxRecord> GetDomainMxRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var mxRecords = DnsResolve<MxRecord>(domainName, RecordType.Mx);
return mxRecords;
}
/// <summary>
/// Check existance of MX record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="mxRecord">MX record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainMxRecordExists(string domainName, string mxRecord)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
if (string.IsNullOrEmpty(mxRecord))
throw new ArgumentNullException(nameof(mxRecord));
var mxDomain = DomainName.Parse(mxRecord);
var records = GetDomainMxRecords(domainName);
return records.Any(
mx => mx.ExchangeDomainName.Equals(mxDomain));
}
/// <summary>
/// Check domain existance
/// </summary>
/// <param name="domainName"></param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="SystemException">if DNS request failed</exception>
/// <returns>true if any DNS record exists and vice versa</returns>
public bool IsDomainExists(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var dnsMessage = GetDnsMessage(domainName);
namespace ASC.Common.Utils;
public class DnsLookup
{
private readonly IDnsResolver _sDnsResolver;
private readonly DnsClient _dnsClient;
public DnsLookup()
{
_dnsClient = DnsClient.Default;
_sDnsResolver = new DnsStubResolver(_dnsClient);
}
/// <summary>
/// Get domain MX records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of MxRecord</returns>
public List<MxRecord> GetDomainMxRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var mxRecords = DnsResolve<MxRecord>(domainName, RecordType.Mx);
return mxRecords;
}
/// <summary>
/// Check existance of MX record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="mxRecord">MX record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainMxRecordExists(string domainName, string mxRecord)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
if (string.IsNullOrEmpty(mxRecord))
{
throw new ArgumentNullException(nameof(mxRecord));
}
var mxDomain = DomainName.Parse(mxRecord);
var records = GetDomainMxRecords(domainName);
return records.Any(
mx => mx.ExchangeDomainName.Equals(mxDomain));
}
/// <summary>
/// Check domain existance
/// </summary>
/// <param name="domainName"></param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="SystemException">if DNS request failed</exception>
/// <returns>true if any DNS record exists and vice versa</returns>
public bool IsDomainExists(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var dnsMessage = GetDnsMessage(domainName);
return dnsMessage.AnswerRecords.Count != 0;
}
/// <summary>
/// Get domain A records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of ARecord</returns>
public List<ARecord> GetDomainARecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var aRecords = DnsResolve<ARecord>(domainName, RecordType.A);
return aRecords;
}
/// <summary>
/// Get domain IP addresses list
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of IPAddress</returns>
public List<IPAddress> GetDomainIPs(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var addresses = _sDnsResolver.ResolveHost(domainName);
return addresses;
}
/// <summary>
/// Get domain TXT records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of TxtRecord</returns>
public List<TxtRecord> GetDomainTxtRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var txtRecords = DnsResolve<TxtRecord>(domainName, RecordType.Txt);
return txtRecords;
}
/// <summary>
/// Check existance of TXT record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="recordValue">TXT record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainTxtRecordExists(string domainName, string recordValue)
{
var txtRecords = GetDomainTxtRecords(domainName);
return
txtRecords.Any(
txtRecord =>
txtRecord.TextData.Trim('\"').Equals(recordValue, StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>
/// Check existance of DKIM record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="dkimSelector">DKIM selector (example is "dkim")</param>
/// <param name="dkimValue">DKIM record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainDkimRecordExists(string domainName, string dkimSelector, string dkimValue)
{
var dkimRecordName = dkimSelector + "._domainkey." + domainName;
var txtRecords = GetDomainTxtRecords(dkimRecordName);
return txtRecords.Any(txtRecord => txtRecord.TextData.Trim('\"').Equals(dkimValue));
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(IPAddress ipAddress, string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
if (ipAddress == null)
throw new ArgumentNullException(nameof(ipAddress));
var domain = DomainName.Parse(domainName);
var ptrDomain = _sDnsResolver.ResolvePtr(ipAddress);
return ptrDomain.Equals(domain);
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="FormatException">if ipAddress is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(string ipAddress, string domainName)
{
return IsDomainPtrRecordExists(IPAddress.Parse(ipAddress), domainName);
}
private DnsMessage GetDnsMessage(string domainName, RecordType? type = null)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var domain = DomainName.Parse(domainName);
var dnsMessage = type.HasValue ? _dnsClient.Resolve(domain, type.Value) : _dnsClient.Resolve(domain);
if ((dnsMessage == null) ||
((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
throw new SystemException(); // DNS request failed
}
return dnsMessage;
}
private List<T> DnsResolve<T>(string domainName, RecordType type)
{
if (string.IsNullOrEmpty(domainName))
throw new ArgumentNullException(nameof(domainName));
var dnsMessage = GetDnsMessage(domainName, type);
return dnsMessage.AnswerRecords.Where(r => r.RecordType == type).Cast<T>().ToList();
}
}
}
}
/// <summary>
/// Get domain A records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of ARecord</returns>
public List<ARecord> GetDomainARecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var aRecords = DnsResolve<ARecord>(domainName, RecordType.A);
return aRecords;
}
/// <summary>
/// Get domain IP addresses list
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of IPAddress</returns>
public List<IPAddress> GetDomainIPs(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var addresses = _sDnsResolver.ResolveHost(domainName);
return addresses;
}
/// <summary>
/// Get domain TXT records
/// </summary>
/// <param name="domainName">domain name</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>list of TxtRecord</returns>
public List<TxtRecord> GetDomainTxtRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var txtRecords = DnsResolve<TxtRecord>(domainName, RecordType.Txt);
return txtRecords;
}
/// <summary>
/// Check existance of TXT record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="recordValue">TXT record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainTxtRecordExists(string domainName, string recordValue)
{
var txtRecords = GetDomainTxtRecords(domainName);
return
txtRecords.Any(
txtRecord =>
txtRecord.TextData.Trim('\"').Equals(recordValue, StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>
/// Check existance of DKIM record in domain DNS
/// </summary>
/// <param name="domainName">domain name</param>
/// <param name="dkimSelector">DKIM selector (example is "dkim")</param>
/// <param name="dkimValue">DKIM record value</param>
/// <exception cref="ArgumentNullException">if domainName is empty</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainDkimRecordExists(string domainName, string dkimSelector, string dkimValue)
{
var dkimRecordName = dkimSelector + "._domainkey." + domainName;
var txtRecords = GetDomainTxtRecords(dkimRecordName);
return txtRecords.Any(txtRecord => txtRecord.TextData.Trim('\"').Equals(dkimValue));
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(IPAddress ipAddress, string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
if (ipAddress == null)
{
throw new ArgumentNullException(nameof(ipAddress));
}
var domain = DomainName.Parse(domainName);
var ptrDomain = _sDnsResolver.ResolvePtr(ipAddress);
return ptrDomain.Equals(domain);
}
/// <summary>
/// Check existance Domain in PTR record
/// </summary>
/// <param name="ipAddress">IP address for PTR check</param>
/// <param name="domainName">PTR domain name</param>
/// <exception cref="ArgumentNullException">if domainName or ipAddress is empty/null</exception>
/// <exception cref="ArgumentException">if domainName is invalid</exception>
/// <exception cref="FormatException">if ipAddress is invalid</exception>
/// <returns>true if exists and vice versa</returns>
public bool IsDomainPtrRecordExists(string ipAddress, string domainName)
{
return IsDomainPtrRecordExists(IPAddress.Parse(ipAddress), domainName);
}
private DnsMessage GetDnsMessage(string domainName, RecordType? type = null)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var domain = DomainName.Parse(domainName);
var dnsMessage = type.HasValue ? _dnsClient.Resolve(domain, type.Value) : _dnsClient.Resolve(domain);
if ((dnsMessage == null) ||
((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
throw new SystemException(); // DNS request failed
}
return dnsMessage;
}
private List<T> DnsResolve<T>(string domainName, RecordType type)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var dnsMessage = GetDnsMessage(domainName, type);
return dnsMessage.AnswerRecords.Where(r => r.RecordType == type).Cast<T>().ToList();
}
}

View File

@ -23,82 +23,94 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class HtmlUtil
{
public static class HtmlUtil
private static readonly Regex _tagReplacer
= new Regex("<[^>]*>", RegexOptions.Multiline | RegexOptions.Compiled);
private static readonly Regex _commentsReplacer
= new Regex("<!--(?s).*?-->", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex _xssReplacer
= new Regex(@"<\s*(style|script)[^>]*>(.*?)<\s*/\s*(style|script)>", RegexOptions.IgnoreCase
| RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.Singleline);
private static readonly Regex _worder =
new Regex(@"\S+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
public static string GetText(string html, int maxLength = 0, string endBlockTemplate = "...")
{
private static readonly Regex tagReplacer = new Regex("<[^>]*>", RegexOptions.Multiline | RegexOptions.Compiled);
private static readonly Regex commentsReplacer = new Regex("<!--(?s).*?-->", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex xssReplacer = new Regex(@"<\s*(style|script)[^>]*>(.*?)<\s*/\s*(style|script)>", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.Singleline);
private static readonly Regex Worder = new Regex(@"\S+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
var unformatedText = string.Empty;
public static string GetText(string html, int maxLength = 0, string endBlockTemplate = "...")
if (!string.IsNullOrEmpty(html))
{
var unformatedText = string.Empty;
if (!string.IsNullOrEmpty(html))
html = _xssReplacer.Replace(html, string.Empty); //Clean malicious tags. <script> <style>
if (string.IsNullOrEmpty(html))
{
html = xssReplacer.Replace(html, string.Empty); //Clean malicious tags. <script> <style>
return html;
}
if (string.IsNullOrEmpty(html))
{
return html;
}
unformatedText = _tagReplacer.Replace(html, string.Empty);
unformatedText = tagReplacer.Replace(html, string.Empty);
if (!string.IsNullOrEmpty(unformatedText))
{
// kill comments
unformatedText = _commentsReplacer.Replace(unformatedText, string.Empty);
unformatedText = unformatedText.Trim();
if (!string.IsNullOrEmpty(unformatedText))
{
// kill comments
unformatedText = commentsReplacer.Replace(unformatedText, string.Empty);
unformatedText = unformatedText.Trim();
if (!string.IsNullOrEmpty(unformatedText))
if (maxLength == 0 || unformatedText.Length < maxLength)
{
if (maxLength == 0 || unformatedText.Length < maxLength)
{
return HttpUtility.HtmlDecode(unformatedText);
}
return HttpUtility.HtmlDecode(unformatedText);
}
//Set maximum length with end block
maxLength = Math.Max(0, maxLength - endBlockTemplate.Length);
var startIndex = Math.Max(0, Math.Min(unformatedText.Length - 1, maxLength));
var countToScan = Math.Max(0, startIndex - 1);
//Set maximum length with end block
maxLength = Math.Max(0, maxLength - endBlockTemplate.Length);
var startIndex = Math.Max(0, Math.Min(unformatedText.Length - 1, maxLength));
var countToScan = Math.Max(0, startIndex - 1);
var lastSpaceIndex = unformatedText.LastIndexOf(' ', startIndex, countToScan);
var lastSpaceIndex = unformatedText.LastIndexOf(' ', startIndex, countToScan);
unformatedText = lastSpaceIndex > 0 && lastSpaceIndex < unformatedText.Length
? unformatedText.Remove(lastSpaceIndex)
: unformatedText.Substring(0, maxLength);
if (!string.IsNullOrEmpty(endBlockTemplate))
{
unformatedText += endBlockTemplate;
}
unformatedText = lastSpaceIndex > 0 && lastSpaceIndex < unformatedText.Length
? unformatedText.Remove(lastSpaceIndex)
: unformatedText.Substring(0, maxLength);
if (!string.IsNullOrEmpty(endBlockTemplate))
{
unformatedText += endBlockTemplate;
}
}
}
return HttpUtility.HtmlDecode(unformatedText);//TODO:!!!
}
public static string ToPlainText(string html)
return HttpUtility.HtmlDecode(unformatedText);//TODO:!!!
}
public static string ToPlainText(string html)
{
return GetText(html);
}
/// <summary>
/// The function highlight all words in htmlText by searchText.
/// </summary>
/// <param name="searchText">the space separated string</param>
/// <param name="htmlText">html for highlight</param>
/// <param name="withoutLink"></param>
/// <returns>highlighted html</returns>
public static string SearchTextHighlight(string searchText, string htmlText, bool withoutLink = false)
{
if (string.IsNullOrEmpty(searchText) || string.IsNullOrEmpty(htmlText))
{
return GetText(html);
return htmlText;
}
/// <summary>
/// The function highlight all words in htmlText by searchText.
/// </summary>
/// <param name="searchText">the space separated string</param>
/// <param name="htmlText">html for highlight</param>
/// <param name="withoutLink"></param>
/// <returns>highlighted html</returns>
public static string SearchTextHighlight(string searchText, string htmlText, bool withoutLink = false)
{
if (string.IsNullOrEmpty(searchText) || string.IsNullOrEmpty(htmlText)) return htmlText;
var regexpstr = Worder.Matches(searchText).Select(m => m.Value).Distinct().Aggregate((r, n) => r + "|" + n);
var wordsFinder = new Regex(Regex.Escape(regexpstr), RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline);
var regexpstr = _worder.Matches(searchText).Select(m => m.Value).Distinct().Aggregate((r, n) => r + "|" + n);
var wordsFinder = new Regex(Regex.Escape(regexpstr), RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline);
return wordsFinder.Replace(htmlText, m => "<span class='searchTextHighlight" + (withoutLink ? " bold" : string.Empty) + "'>" + m.Value + "</span>");
}
}
}

View File

@ -26,186 +26,190 @@
using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
namespace System.Web
{
public static class HttpRequestExtensions
{
public static readonly string UrlRewriterHeader = "X-REWRITER-URL";
public static Uri GetUrlRewriter(this HttpRequest request)
{
return request != null ? GetUrlRewriter(request.Headers, request) : null;
}
public static Uri Url(this HttpRequest request)
{
return request != null ? new Uri(request.GetDisplayUrl()) : null;
}
/*public static Uri GetUrlRewriter(this HttpRequestBase request)
{
return request != null ? GetUrlRewriter(request.Headers, request.Url) : null;
}*/
public static Uri GetUrlRewriter(IHeaderDictionary headers, HttpRequest request)
{
if (headers != null)
{
var h = headers[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (request != null && rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
namespace System.Web;
if (request != null && request.Query != null)
{
var h = request.Query[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
return request.Url();
}
public static Uri PushRewritenUri(this HttpContext context)
{
return context != null ? PushRewritenUri(context, GetUrlRewriter(context.Request)) : null;
}
public static Uri PushRewritenUri(this HttpContext context, Uri rewrittenUri)
{
Uri oldUri = null;
if (context != null)
{
var request = context.Request;
var url = new Uri(request.GetDisplayUrl());
if (url != rewrittenUri)
{
var requestUri = url;
try
{
//Push it
request.Headers.SetCommaSeparatedValues("HTTPS", rewrittenUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? "on" : "off");
request.Headers.SetCommaSeparatedValues("SERVER_NAME", rewrittenUri.Host);
request.Headers.SetCommaSeparatedValues("SERVER_PORT",
rewrittenUri.Port.ToString(CultureInfo.InvariantCulture));
if (rewrittenUri.IsDefaultPort)
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host);
}
else
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host + ":" + requestUri.Port);
}
//Hack:
typeof(HttpRequest).InvokeMember("_url",
BindingFlags.NonPublic | BindingFlags.SetField |
BindingFlags.Instance,
null, request,
new object[] { null });
oldUri = requestUri;
context.Items["oldUri"] = oldUri;
}
catch (Exception)
{
}
}
}
return oldUri;
}
public static Uri PopRewritenUri(this HttpContext context)
{
if (context != null && context.Items["oldUri"] != null)
{
var rewriteTo = context.Items["oldUri"] as Uri;
if (rewriteTo != null)
{
return PushRewritenUri(context, rewriteTo);
}
}
return null;
}
public static bool DesktopApp(this HttpRequest request)
public static class HttpRequestExtensions
{
public static readonly string UrlRewriterHeader = "X-REWRITER-URL";
public static Uri GetUrlRewriter(this HttpRequest request)
{
return request != null ? GetUrlRewriter(request.Headers, request) : null;
}
public static Uri Url(this HttpRequest request)
{
return request != null ? new Uri(request.GetDisplayUrl()) : null;
}
/*public static Uri GetUrlRewriter(this HttpRequestBase request)
{
return request != null ? GetUrlRewriter(request.Headers, request.Url) : null;
}*/
public static Uri GetUrlRewriter(IHeaderDictionary headers, HttpRequest request)
{
if (headers != null)
{
return request != null
&& (!string.IsNullOrEmpty(request.Query["desktop"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("AscDesktopEditor"));
}
public static bool SailfishApp(this HttpRequest request)
{
return request != null
&& (!string.IsNullOrEmpty(request.Headers["sailfish"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("SailfishOS"));
}
private static Uri ParseRewriterUrl(string s)
{
if (string.IsNullOrEmpty(s))
{
return null;
}
const StringComparison cmp = StringComparison.OrdinalIgnoreCase;
var h = headers[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (request != null && rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
if (request != null && request.Query != null)
{
var h = request.Query[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (rewriterUri != null)
{
var result = new UriBuilder()
{
Scheme = rewriterUri.Scheme,
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
return request.Url();
}
public static Uri PushRewritenUri(this HttpContext context)
{
return context != null ? PushRewritenUri(context, GetUrlRewriter(context.Request)) : null;
}
public static Uri PushRewritenUri(this HttpContext context, Uri rewrittenUri)
{
Uri oldUri = null;
if (context != null)
{
var request = context.Request;
var url = new Uri(request.GetDisplayUrl());
if (url != rewrittenUri)
{
var requestUri = url;
try
{
//Push it
request.Headers.SetCommaSeparatedValues("HTTPS", rewrittenUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? "on" : "off");
request.Headers.SetCommaSeparatedValues("SERVER_NAME", rewrittenUri.Host);
request.Headers.SetCommaSeparatedValues("SERVER_PORT",
rewrittenUri.Port.ToString(CultureInfo.InvariantCulture));
if (rewrittenUri.IsDefaultPort)
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host);
}
else
{
request.Headers.SetCommaSeparatedValues("HTTP_HOST",
rewrittenUri.Host + ":" + requestUri.Port);
}
//Hack:
typeof(HttpRequest).InvokeMember("_url",
BindingFlags.NonPublic | BindingFlags.SetField |
BindingFlags.Instance,
null, request,
new object[] { null });
oldUri = requestUri;
context.Items["oldUri"] = oldUri;
}
catch (Exception) { }
}
}
return oldUri;
}
public static Uri PopRewritenUri(this HttpContext context)
{
if (context != null && context.Items["oldUri"] != null)
{
var rewriteTo = context.Items["oldUri"] as Uri;
if (rewriteTo != null)
{
return PushRewritenUri(context, rewriteTo);
}
}
return null;
}
public static bool DesktopApp(this HttpRequest request)
{
return request != null
&& (!string.IsNullOrEmpty(request.Query["desktop"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("AscDesktopEditor"));
}
public static bool SailfishApp(this HttpRequest request)
{
return request != null
&& (!string.IsNullOrEmpty(request.Headers["sailfish"])
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("SailfishOS"));
}
public static string GetUserHostAddress(this HttpRequest request)
{
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
}
private static Uri ParseRewriterUrl(string s)
{
if (string.IsNullOrEmpty(s))
{
return null;
}
const StringComparison cmp = StringComparison.OrdinalIgnoreCase;
if (0 < s.Length && s.StartsWith('0'))
{
s = Uri.UriSchemeHttp + s.Substring(1);
}
else if (3 < s.Length && s.StartsWith("OFF", cmp))
{
s = Uri.UriSchemeHttp + s.Substring(3);
}
{
s = Uri.UriSchemeHttp + s.Substring(1);
}
else if (3 < s.Length && s.StartsWith("OFF", cmp))
{
s = Uri.UriSchemeHttp + s.Substring(3);
}
else if (0 < s.Length && s.StartsWith('1'))
{
s = Uri.UriSchemeHttps + s.Substring(1);
}
else if (2 < s.Length && s.StartsWith("ON", cmp))
{
s = Uri.UriSchemeHttps + s.Substring(2);
}
else if (s.StartsWith(Uri.UriSchemeHttp + "%3A%2F%2F", cmp) || s.StartsWith(Uri.UriSchemeHttps + "%3A%2F%2F", cmp))
{
s = HttpUtility.UrlDecode(s);
}
Uri.TryCreate(s, UriKind.Absolute, out var result);
return result;
}
public static string GetUserHostAddress(this HttpRequest request)
{
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
}
}
}
{
s = Uri.UriSchemeHttps + s.Substring(1);
}
else if (2 < s.Length && s.StartsWith("ON", cmp))
{
s = Uri.UriSchemeHttps + s.Substring(2);
}
else if (s.StartsWith(Uri.UriSchemeHttp + "%3A%2F%2F", cmp) || s.StartsWith(Uri.UriSchemeHttps + "%3A%2F%2F", cmp))
{
s = HttpUtility.UrlDecode(s);
}
Uri.TryCreate(s, UriKind.Absolute, out var result);
return result;
}
}

View File

@ -27,70 +27,69 @@
using Formatting = Newtonsoft.Json.Formatting;
using IJsonSerializer = JWT.IJsonSerializer;
namespace ASC.Web.Core.Files
namespace ASC.Web.Core.Files;
public static class JsonWebToken
{
public static class JsonWebToken
public static string Encode(object payload, string key)
{
public static string Encode(object payload, string key)
{
var (serializer, algorithm, urlEncoder) = GetSettings();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
var (serializer, algorithm, urlEncoder) = GetSettings();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder.Encode(payload, key);
}
public static string Decode(string token, string key, bool verify = true, bool baseSerializer = false)
{
var (serializer, algorithm, urlEncoder) = GetSettings(baseSerializer);
var provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
var decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
return decoder.Decode(token, key, verify);
}
private static (IJsonSerializer, IJwtAlgorithm, IBase64UrlEncoder) GetSettings(bool baseSerializer = false)
{
return (baseSerializer ? (IJsonSerializer)new JsonNetSerializer() : new JwtSerializer(), new HMACSHA256Algorithm(), new JwtBase64UrlEncoder());
}
return encoder.Encode(payload, key);
}
public class JwtSerializer : IJsonSerializer
public static string Decode(string token, string key, bool verify = true, bool baseSerializer = false)
{
private class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
var contract = base.CreateDictionaryContract(objectType);
var (serializer, algorithm, urlEncoder) = GetSettings(baseSerializer);
contract.DictionaryKeyResolver = propertyName => propertyName;
var provider = new UtcDateTimeProvider();
IJwtValidator validator = new JwtValidator(serializer, provider);
return contract;
}
}
var decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
public string Serialize(object obj)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return decoder.Decode(token, key, verify);
}
return JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
}
public T Deserialize<T>(string json)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return JsonConvert.DeserializeObject<T>(json, settings);
}
private static (IJsonSerializer, IJwtAlgorithm, IBase64UrlEncoder) GetSettings(bool baseSerializer = false)
{
return (baseSerializer ? (IJsonSerializer)new JsonNetSerializer() : new JwtSerializer(), new HMACSHA256Algorithm(), new JwtBase64UrlEncoder());
}
}
public class JwtSerializer : IJsonSerializer
{
private class CamelCaseExceptDictionaryKeysResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonDictionaryContract CreateDictionaryContract(Type objectType)
{
var contract = base.CreateDictionaryContract(objectType);
contract.DictionaryKeyResolver = propertyName => propertyName;
return contract;
}
}
public string Serialize(object obj)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
}
public T Deserialize<T>(string json)
{
var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCaseExceptDictionaryKeysResolver(),
NullValueHandling = NullValueHandling.Ignore,
};
return JsonConvert.DeserializeObject<T>(json, settings);
}
}

View File

@ -23,46 +23,48 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class MailAddressUtils
{
public static class MailAddressUtils
public static MailAddress Create(string address)
{
public static MailAddress Create(string address)
if (!string.IsNullOrEmpty(address))
{
if (!string.IsNullOrEmpty(address))
var firstPos = address.IndexOf('"');
var lastPos = address.LastIndexOf('"');
if (firstPos != -1 && firstPos < lastPos && address.IndexOf('"', firstPos + 1, lastPos - firstPos - 1) != -1)
{
var firstPos = address.IndexOf('"');
var lastPos = address.LastIndexOf('"');
if (firstPos != -1 && firstPos < lastPos && address.IndexOf('"', firstPos + 1, lastPos - firstPos - 1) != -1)
{
address = new StringBuilder(address).Replace("\"", string.Empty, firstPos + 1, lastPos - firstPos - 1).ToString();
}
address = new StringBuilder(address).Replace("\"", string.Empty, firstPos + 1, lastPos - firstPos - 1).ToString();
}
return new MailAddress(address);
}
public static MailAddress Create(string address, string displayName)
return new MailAddress(address);
}
public static MailAddress Create(string address, string displayName)
{
if (!string.IsNullOrEmpty(displayName))
{
if (!string.IsNullOrEmpty(displayName))
displayName = displayName.Replace("\"", string.Empty);
if (125 < displayName.Length)
{
displayName = displayName.Replace("\"", string.Empty);
if (125 < displayName.Length)
{
displayName = displayName.Substring(0, 125);
}
displayName = displayName.Substring(0, 125);
}
return Create(ToSmtpAddress(address, displayName));
}
public static string ToEncodedString(this MailAddress m)
{
return ToSmtpAddress(m.Address, MimeHeaderUtils.EncodeMime(m.DisplayName));
}
return Create(ToSmtpAddress(address, displayName));
}
public static string ToEncodedString(this MailAddress m)
{
return ToSmtpAddress(m.Address, MimeHeaderUtils.EncodeMime(m.DisplayName));
}
private static string ToSmtpAddress(string address, string displayName)
{
return $"\"{displayName}\" <{address}>";
}
private static string ToSmtpAddress(string address, string displayName)
{
return $"\"{displayName}\" <{address}>";
}
}

View File

@ -23,47 +23,50 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class MimeHeaderUtils
{
public static class MimeHeaderUtils
public static string EncodeMime(string mimeHeaderValue)
{
public static string EncodeMime(string mimeHeaderValue)
{
return EncodeMime(mimeHeaderValue, Encoding.UTF8, false);
}
return EncodeMime(mimeHeaderValue, Encoding.UTF8, false);
}
public static string EncodeMime(string mimeHeaderValue, Encoding charset, bool split)
public static string EncodeMime(string mimeHeaderValue, Encoding charset, bool split)
{
if (MustEncode(mimeHeaderValue))
{
if (MustEncode(mimeHeaderValue))
var result = new StringBuilder();
var data = charset.GetBytes(mimeHeaderValue);
var maxEncodedTextSize = split ? 75 - ("=?" + charset.WebName + "?" + "B"/*Base64 encode*/ + "?" + "?=").Length : int.MaxValue;
result.Append("=?" + charset.WebName + "?B?");
var stored = 0;
var base64 = Convert.ToBase64String(data);
for (var i = 0; i < base64.Length; i += 4)
{
var result = new StringBuilder();
var data = charset.GetBytes(mimeHeaderValue);
var maxEncodedTextSize = split ? 75 - ("=?" + charset.WebName + "?" + "B"/*Base64 encode*/ + "?" + "?=").Length : int.MaxValue;
result.Append("=?" + charset.WebName + "?B?");
var stored = 0;
var base64 = Convert.ToBase64String(data);
for (var i = 0; i < base64.Length; i += 4)
// Encoding buffer full, create new encoded-word.
if (stored + 4 > maxEncodedTextSize)
{
// Encoding buffer full, create new encoded-word.
if (stored + 4 > maxEncodedTextSize)
{
result.Append("?=\r\n =?" + charset.WebName + "?B?");
stored = 0;
}
result.Append(base64, i, 4);
stored += 4;
result.Append("?=\r\n =?" + charset.WebName + "?B?");
stored = 0;
}
result.Append("?=");
return result.ToString();
result.Append(base64, i, 4);
stored += 4;
}
return mimeHeaderValue;
result.Append("?=");
return result.ToString();
}
public static bool MustEncode(string text)
{
return !string.IsNullOrEmpty(text) && text.Any(c => c > 127);
}
return mimeHeaderValue;
}
public static bool MustEncode(string text)
{
return !string.IsNullOrEmpty(text) && text.Any(c => c > 127);
}
}

View File

@ -23,19 +23,20 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class RandomString
{
public static class RandomString
public static string Generate(int length)
{
public static string Generate(int length)
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
var res = new StringBuilder();
while (0 < length--)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
var res = new StringBuilder();
while (0 < length--)
{
res.Append(valid[RandomNumberGenerator.GetInt32(valid.Length)]);
}
return res.ToString();
}
return res.ToString();
}
}

View File

@ -23,63 +23,64 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
[Singletone]
public class Signature
{
[Singletone]
public class Signature
private readonly MachinePseudoKeys _machinePseudoKeys;
public Signature(MachinePseudoKeys machinePseudoKeys)
{
public Signature(MachinePseudoKeys machinePseudoKeys)
{
MachinePseudoKeys = machinePseudoKeys;
}
private MachinePseudoKeys MachinePseudoKeys { get; }
public string Create<T>(T obj)
{
return Create(obj, Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()));
}
public static string Create<T>(T obj, string secret)
{
var str = JsonConvert.SerializeObject(obj);
var payload = GetHashBase64(str + secret) + "?" + str;
return WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(payload));
}
public T Read<T>(string signature)
{
return Read<T>(signature, Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()));
}
public static T Read<T>(string signature, string secret)
{
try
{
var rightSignature = signature.Replace("\"", "");
var payloadParts = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(rightSignature)).Split('?');
if (GetHashBase64(payloadParts[1] + secret) == payloadParts[0])
{
//Sig correct
return JsonConvert.DeserializeObject<T>(payloadParts[1]);
}
}
catch (Exception)
{
}
return default;
}
private static string GetHashBase64(string str)
{
using var sha256 = SHA256.Create();
return Convert.ToBase64String(sha256.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
private static string GetHashBase64MD5(string str)
{
using var md5 = MD5.Create();
return Convert.ToBase64String(md5.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
_machinePseudoKeys = machinePseudoKeys;
}
}
public string Create<T>(T obj)
{
return Create(obj, Encoding.UTF8.GetString(_machinePseudoKeys.GetMachineConstant()));
}
public static string Create<T>(T obj, string secret)
{
var str = JsonConvert.SerializeObject(obj);
var payload = GetHashBase64(str + secret) + "?" + str;
return WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(payload));
}
public T Read<T>(string signature)
{
return Read<T>(signature, Encoding.UTF8.GetString(_machinePseudoKeys.GetMachineConstant()));
}
public static T Read<T>(string signature, string secret)
{
try
{
var rightSignature = signature.Replace("\"", "");
var payloadParts = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(rightSignature)).Split('?');
if (GetHashBase64(payloadParts[1] + secret) == payloadParts[0])
{
return JsonConvert.DeserializeObject<T>(payloadParts[1]); //Sig correct
}
}
catch (Exception) { }
return default;
}
private static string GetHashBase64(string str)
{
using var sha256 = SHA256.Create();
return Convert.ToBase64String(sha256.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
private static string GetHashBase64MD5(string str)
{
using var md5 = MD5.Create();
return Convert.ToBase64String(md5.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
}

View File

@ -23,291 +23,314 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
[Singletone]
public class TimeZoneConverter
{
[Singletone]
public class TimeZoneConverter
private TimeZoneInfo _defaultTimeZone;
private IEnumerable<MapZone> _mapZones;
private bool _customMode;
private bool _isMono;
private Dictionary<string, string> _translations;
private readonly IConfiguration _configuration;
private readonly ILog _logger;
public TimeZoneConverter(IConfiguration configuration, IOptionsMonitor<ILog> option)
{
private TimeZoneInfo defaultTimeZone;
private IEnumerable<MapZone> _mapZones;
private bool _customMode;
private bool _isMono;
private Dictionary<string, string> _translations;
private IConfiguration Configuration { get; }
private ILog Log { get; }
public TimeZoneConverter(IConfiguration configuration, IOptionsMonitor<ILog> option)
{
Log = option.CurrentValue;
Configuration = configuration;
InitMapZones();
InitTranslations();
}
private void InitMapZones()
{
try
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.windowsZones.xml");
var xml = XElement.Load(stream);
_mapZones = from row in xml.XPathSelectElements("*/mapTimezones/mapZone")
let olsonTimeZones = row.Attribute("type").Value.Split(' ')
from olsonTimeZone in olsonTimeZones
select new MapZone
{
OlsonTimeZoneId = olsonTimeZone,
WindowsTimeZoneId = row.Attribute("other").Value,
Territory = row.Attribute("territory").Value
};
_mapZones = _mapZones.ToList();
}
catch (Exception error)
{
_mapZones = new MapZone[0];
Log.Error(error);
}
}
_logger = option.CurrentValue;
_configuration = configuration;
InitMapZones();
InitTranslations();
}
public string GetTimeZoneDisplayName(TimeZoneInfo tz)
public string GetTimeZoneDisplayName(TimeZoneInfo tz)
{
var displayName = GetTimeZoneName(tz);
if (!displayName.StartsWith("(UTC") && !displayName.StartsWith("UTC"))
{
var displayName = GetTimeZoneName(tz);
if (!displayName.StartsWith("(UTC") && !displayName.StartsWith("UTC"))
if (tz.BaseUtcOffset != TimeSpan.Zero)
{
if (tz.BaseUtcOffset != TimeSpan.Zero)
{
var offSet = tz.BaseUtcOffset < TimeSpan.Zero ? "-" : "+";
var name = tz.BaseUtcOffset.ToString(@"hh\:mm");
displayName = $"(UTC{offSet}{name}) {displayName}";
}
else
{
displayName = "(UTC) " + displayName;
}
var offSet = tz.BaseUtcOffset < TimeSpan.Zero ? "-" : "+";
var name = tz.BaseUtcOffset.ToString(@"hh\:mm");
displayName = $"(UTC{offSet}{name}) {displayName}";
}
return displayName;
}
public string OlsonTzId2WindowsTzId(string olsonTimeZoneId, bool defaultIfNoMatch = true)
{
var mapZone = GetMapZoneByWindowsTzId(olsonTimeZoneId);
if (mapZone != null)
return olsonTimeZoneId; //already Windows
mapZone = GetMapZoneByOlsonTzId(olsonTimeZoneId);
if (mapZone != null)
return mapZone.WindowsTimeZoneId;
Log.Error("OlsonTimeZone " + olsonTimeZoneId + " not found");
return defaultIfNoMatch ? "UTC" : null;
}
public string WindowsTzId2OlsonTzId(string windowsTimeZoneId, bool defaultIfNoMatch = true)
{
var mapZone = GetMapZoneByOlsonTzId(windowsTimeZoneId);
if (mapZone != null)
return windowsTimeZoneId; //already Olson
mapZone = GetMapZoneByWindowsTzId(windowsTimeZoneId);
if (mapZone != null)
return mapZone.OlsonTimeZoneId;
Log.Error("WindowsTimeZone " + windowsTimeZoneId + " not found");
return defaultIfNoMatch ? "Etc/GMT" : null;
}
public TimeZoneInfo GetTimeZone(string timeZoneId, bool defaultIfNoMatch = true)
{
var defaultTimezone = GetTimeZoneDefault();
if (string.IsNullOrEmpty(timeZoneId))
else
{
displayName = "(UTC) " + displayName;
}
}
return displayName;
}
public string OlsonTzId2WindowsTzId(string olsonTimeZoneId, bool defaultIfNoMatch = true)
{
var mapZone = GetMapZoneByWindowsTzId(olsonTimeZoneId);
if (mapZone != null)
{
return olsonTimeZoneId; //already Windows
}
mapZone = GetMapZoneByOlsonTzId(olsonTimeZoneId);
if (mapZone != null)
{
return mapZone.WindowsTimeZoneId;
}
_logger.Error($"OlsonTimeZone {olsonTimeZoneId} not found");
return defaultIfNoMatch ? "UTC" : null;
}
public string WindowsTzId2OlsonTzId(string windowsTimeZoneId, bool defaultIfNoMatch = true)
{
var mapZone = GetMapZoneByOlsonTzId(windowsTimeZoneId);
if (mapZone != null)
{
return windowsTimeZoneId; //already Olson
}
mapZone = GetMapZoneByWindowsTzId(windowsTimeZoneId);
if (mapZone != null)
{
return mapZone.OlsonTimeZoneId;
}
_logger.Error($"WindowsTimeZone {windowsTimeZoneId} not found");
return defaultIfNoMatch ? "Etc/GMT" : null;
}
public TimeZoneInfo GetTimeZone(string timeZoneId, bool defaultIfNoMatch = true)
{
var defaultTimezone = GetTimeZoneDefault();
if (string.IsNullOrEmpty(timeZoneId))
{
return defaultIfNoMatch ? defaultTimezone : null;
}
try
{
return TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
}
catch (TimeZoneNotFoundException)
{
try
{
var mapZone = GetMapZoneByOlsonTzId(timeZoneId);
if (mapZone != null)
{
return TimeZoneInfo.FindSystemTimeZoneById(mapZone.WindowsTimeZoneId);
}
mapZone = GetMapZoneByWindowsTzId(timeZoneId);
if (mapZone != null)
{
return TimeZoneInfo.FindSystemTimeZoneById(mapZone.OlsonTimeZoneId);
}
_logger.InfoFormat("TimeZone {0} not found", timeZoneId);
return defaultIfNoMatch ? GetTimeZoneByOffset(timeZoneId) ?? defaultTimezone : null;
}
catch (Exception error)
{
_logger.Error(error);
return defaultIfNoMatch ? defaultTimezone : null;
}
try
{
return TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
}
catch (TimeZoneNotFoundException)
{
try
{
var mapZone = GetMapZoneByOlsonTzId(timeZoneId);
if (mapZone != null)
{
return TimeZoneInfo.FindSystemTimeZoneById(mapZone.WindowsTimeZoneId);
}
mapZone = GetMapZoneByWindowsTzId(timeZoneId);
if (mapZone != null)
{
return TimeZoneInfo.FindSystemTimeZoneById(mapZone.OlsonTimeZoneId);
}
Log.InfoFormat("TimeZone {0} not found", timeZoneId);
return defaultIfNoMatch ? GetTimeZoneByOffset(timeZoneId) ?? defaultTimezone : null;
}
catch (Exception error)
{
Log.Error(error);
return defaultIfNoMatch ? defaultTimezone : null;
}
}
catch (Exception error)
{
Log.Error(error);
return defaultIfNoMatch ? defaultTimezone : null;
}
}
private MapZone GetMapZoneByOlsonTzId(string olsonTimeZoneId)
{
return _mapZones.FirstOrDefault(x =>
x.OlsonTimeZoneId.Equals(olsonTimeZoneId, StringComparison.CurrentCultureIgnoreCase));
}
private MapZone GetMapZoneByWindowsTzId(string windowsTimeZoneId)
{
return _mapZones.FirstOrDefault(x =>
x.WindowsTimeZoneId.Equals(windowsTimeZoneId, StringComparison.CurrentCultureIgnoreCase) &&
x.Territory.Equals("001", StringComparison.CurrentCultureIgnoreCase));
}
private TimeZoneInfo GetTimeZoneByOffset(string timeZoneId)
{
var systemTimeZones = TimeZoneInfo.GetSystemTimeZones();
var timeZone = systemTimeZones.FirstOrDefault(tz =>
tz.DisplayName == timeZoneId ||
tz.StandardName == timeZoneId ||
tz.DaylightName == timeZoneId);
if (timeZone != null) return timeZone;
var regex = new Regex(@"[+-][0-9]{2}:[0-9]{2}\b");
var offsetStr = regex.Match(timeZoneId).Value.TrimStart('+');
if (string.IsNullOrEmpty(offsetStr)) return null;
if (!TimeSpan.TryParse(offsetStr, out var offset))
return null;
return systemTimeZones.FirstOrDefault(tz => tz.BaseUtcOffset == offset);
}
private void InitTranslations()
{
try
{
_customMode = Configuration["core:custom-mode"] == "true";
if (!_customMode)
{
_translations = new Dictionary<string, string>();
return;
}
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.timeZoneNames.xml");
var xml = XElement.Load(stream);
_translations = (from row in xml.XPathSelectElements("*/zone")
select new KeyValuePair<string, string>(row.Attribute("type").Value, row.Value)
).ToDictionary(item => item.Key, item => item.Value);
}
catch (Exception error)
{
_translations = new Dictionary<string, string>();
Log.Error(error);
}
}
public string GetTimeZoneName(TimeZoneInfo timeZone)
{
if (!_customMode)
return _isMono ? timeZone.Id : timeZone.DisplayName;
return _translations.ContainsKey(timeZone.Id) ? _translations[timeZone.Id] : timeZone.DisplayName;
}
catch (Exception error)
{
_logger.Error(error);
return defaultIfNoMatch ? defaultTimezone : null;
}
}
private MapZone GetMapZoneByOlsonTzId(string olsonTimeZoneId)
{
return _mapZones.FirstOrDefault(x =>
x.OlsonTimeZoneId.Equals(olsonTimeZoneId, StringComparison.CurrentCultureIgnoreCase));
}
private MapZone GetMapZoneByWindowsTzId(string windowsTimeZoneId)
{
return _mapZones.FirstOrDefault(x =>
x.WindowsTimeZoneId.Equals(windowsTimeZoneId, StringComparison.CurrentCultureIgnoreCase) &&
x.Territory.Equals("001", StringComparison.CurrentCultureIgnoreCase));
}
private TimeZoneInfo GetTimeZoneByOffset(string timeZoneId)
{
var systemTimeZones = TimeZoneInfo.GetSystemTimeZones();
var timeZone = systemTimeZones.FirstOrDefault(tz =>
tz.DisplayName == timeZoneId ||
tz.StandardName == timeZoneId ||
tz.DaylightName == timeZoneId);
if (timeZone != null)
{
return timeZone;
}
private TimeZoneInfo GetTimeZoneDefault()
{
if (defaultTimeZone == null)
{
try
{
var tz = TimeZoneInfo.Local;
if (Path.DirectorySeparatorChar == '/')
{
if (tz.StandardName == "UTC" || tz.StandardName == "UCT")
{
tz = TimeZoneInfo.Utc;
}
else
{
var id = string.Empty;
if (File.Exists("/etc/timezone"))
{
_isMono = true;
id = File.ReadAllText("/etc/timezone").Trim();
}
if (string.IsNullOrEmpty(id))
{
var psi = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = "date +%Z",
RedirectStandardOutput = true,
UseShellExecute = false,
};
using var p = Process.Start(psi);
if (p.WaitForExit(1000))
{
id = p.StandardOutput.ReadToEnd();
}
p.Close();
}
if (!string.IsNullOrEmpty(id))
{
tz = TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(z => z.Id == id) ?? tz;
}
}
}
defaultTimeZone = tz;
}
catch (Exception)
{
// ignore
defaultTimeZone = TimeZoneInfo.Utc;
}
}
return defaultTimeZone;
var regex = new Regex(@"[+-][0-9]{2}:[0-9]{2}\b");
var offsetStr = regex.Match(timeZoneId).Value.TrimStart('+');
if (string.IsNullOrEmpty(offsetStr))
{
return null;
}
private class MapZone
{
public string OlsonTimeZoneId { get; set; }
public string WindowsTimeZoneId { get; set; }
public string Territory { get; set; }
}
}
if (!TimeSpan.TryParse(offsetStr, out var offset))
{
return null;
}
return systemTimeZones.FirstOrDefault(tz => tz.BaseUtcOffset == offset);
}
private void InitMapZones()
{
try
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.windowsZones.xml");
var xml = XElement.Load(stream);
_mapZones = from row in xml.XPathSelectElements("*/mapTimezones/mapZone")
let olsonTimeZones = row.Attribute("type").Value.Split(' ')
from olsonTimeZone in olsonTimeZones
select new MapZone
{
OlsonTimeZoneId = olsonTimeZone,
WindowsTimeZoneId = row.Attribute("other").Value,
Territory = row.Attribute("territory").Value
};
_mapZones = _mapZones.ToList();
}
catch (Exception error)
{
_mapZones = new MapZone[0];
_logger.Error(error);
}
}
public string GetTimeZoneName(TimeZoneInfo timeZone)
{
if (!_customMode)
{
return _isMono ? timeZone.Id : timeZone.DisplayName;
}
return _translations.ContainsKey(timeZone.Id) ? _translations[timeZone.Id] : timeZone.DisplayName;
}
private TimeZoneInfo GetTimeZoneDefault()
{
if (_defaultTimeZone == null)
{
try
{
var tz = TimeZoneInfo.Local;
if (Path.DirectorySeparatorChar == '/')
{
if (tz.StandardName == "UTC" || tz.StandardName == "UCT")
{
tz = TimeZoneInfo.Utc;
}
else
{
var id = string.Empty;
if (File.Exists("/etc/timezone"))
{
_isMono = true;
id = File.ReadAllText("/etc/timezone").Trim();
}
if (string.IsNullOrEmpty(id))
{
var psi = new ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = "date +%Z",
RedirectStandardOutput = true,
UseShellExecute = false,
};
using var p = Process.Start(psi);
if (p.WaitForExit(1000))
{
id = p.StandardOutput.ReadToEnd();
}
p.Close();
}
if (!string.IsNullOrEmpty(id))
{
tz = TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(z => z.Id == id) ?? tz;
}
}
}
_defaultTimeZone = tz;
}
catch (Exception)
{
// ignore
_defaultTimeZone = TimeZoneInfo.Utc;
}
}
return _defaultTimeZone;
}
private void InitTranslations()
{
try
{
_customMode = _configuration["core:custom-mode"] == "true";
if (!_customMode)
{
_translations = new Dictionary<string, string>();
return;
}
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.timeZoneNames.xml");
var xml = XElement.Load(stream);
_translations = (from row in xml.XPathSelectElements("*/zone")
select new KeyValuePair<string, string>(row.Attribute("type").Value, row.Value)
).ToDictionary(item => item.Key, item => item.Value);
}
catch (Exception error)
{
_translations = new Dictionary<string, string>();
_logger.Error(error);
}
}
private class MapZone
{
public string OlsonTimeZoneId { get; set; }
public string WindowsTimeZoneId { get; set; }
public string Territory { get; set; }
}
}

View File

@ -23,66 +23,72 @@
*
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public class TextLoader : ResourceLoader
{
public override void Init(Commons.Collections.ExtendedProperties configuration)
{
//nothing to configure
}
public override Stream GetResourceStream(string source)
{
return new MemoryStream(Encoding.UTF8.GetBytes(source));
}
public override long GetLastModified(NVelocity.Runtime.Resource.Resource resource)
{
return 1;
}
public override bool IsSourceModified(NVelocity.Runtime.Resource.Resource resource)
{
return false;
}
}
public static class VelocityFormatter
{
public class TextLoader : ResourceLoader
{
public override void Init(Commons.Collections.ExtendedProperties configuration)
{
//nothing to configure
}
public override Stream GetResourceStream(string source)
{
return new MemoryStream(Encoding.UTF8.GetBytes(source));
}
public override long GetLastModified(NVelocity.Runtime.Resource.Resource resource)
{
return 1;
}
public override bool IsSourceModified(NVelocity.Runtime.Resource.Resource resource)
{
return false;
}
}
public static class VelocityFormatter
{
private static bool initialized;
private static readonly ConcurrentDictionary<string, Template> patterns = new ConcurrentDictionary<string, Template>();
public static string FormatText(string templateText, IDictionary<string, object> values)
{
var nvelocityContext = new VelocityContext();
foreach (var tagValue in values)
nvelocityContext.Put(tagValue.Key, tagValue.Value);
return FormatText(templateText, nvelocityContext);
}
public static string FormatText(string templateText, VelocityContext context)
{
if (!initialized)
{
var properties = new Commons.Collections.ExtendedProperties();
properties.AddProperty("resource.loader", "custom");
properties.AddProperty("custom.resource.loader.class", "ASC.Common.Utils.TextLoader; ASC.Common");
properties.AddProperty("input.encoding", Encoding.UTF8.WebName);
properties.AddProperty("output.encoding", Encoding.UTF8.WebName);
Velocity.Init(properties);
initialized = true;
}
using var writer = new StringWriter();
var key = templateText.GetHashCode().ToString();
if (!patterns.TryGetValue(key, out var template))
{
template = Velocity.GetTemplate(templateText);
patterns.TryAdd(key, template);
}
template.Merge(context, writer);
return writer.GetStringBuilder().ToString();
}
}
private static bool _initialized;
private static readonly ConcurrentDictionary<string, Template> _patterns = new ConcurrentDictionary<string, Template>();
public static string FormatText(string templateText, IDictionary<string, object> values)
{
var nvelocityContext = new VelocityContext();
foreach (var tagValue in values)
{
nvelocityContext.Put(tagValue.Key, tagValue.Value);
}
return FormatText(templateText, nvelocityContext);
}
public static string FormatText(string templateText, VelocityContext context)
{
if (!_initialized)
{
var properties = new Commons.Collections.ExtendedProperties();
properties.AddProperty("resource.loader", "custom");
properties.AddProperty("custom.resource.loader.class", "ASC.Common.Utils.TextLoader; ASC.Common");
properties.AddProperty("input.encoding", Encoding.UTF8.WebName);
properties.AddProperty("output.encoding", Encoding.UTF8.WebName);
Velocity.Init(properties);
_initialized = true;
}
using var writer = new StringWriter();
var key = templateText.GetHashCode().ToString();
if (!_patterns.TryGetValue(key, out var template))
{
template = Velocity.GetTemplate(templateText);
_patterns.TryAdd(key, template);
}
template.Merge(context, writer);
return writer.GetStringBuilder().ToString();
}
}

View File

@ -24,81 +24,97 @@
*/
namespace ASC.Common.Utils
namespace ASC.Common.Utils;
public static class Wildcard
{
public static class Wildcard
public static bool WildcardMatch(this string input, string pattern)
{
public static bool WildcardMatch(this string input, string pattern)
return WildcardMatch(input, pattern, true);
}
public static bool WildcardMatch(this string input, string pattern, bool ignoreCase)
{
if (!string.IsNullOrEmpty(input))
{
return WildcardMatch(input, pattern, true);
return IsMatch(pattern, input, ignoreCase);
}
public static bool WildcardMatch(this string input, string pattern, bool ignoreCase)
return false;
}
public static bool IsMatch(string pattern, string input)
{
return IsMatch(pattern, input, true);
}
public static bool IsMatch(string pattern, string input, bool ignoreCase)
{
var offsetInput = 0;
var isAsterix = false;
int i = 0;
while (i < pattern.Length)
{
if (!string.IsNullOrEmpty(input))
switch (pattern[i])
{
return IsMatch(pattern, input, ignoreCase);
case '?':
isAsterix = false;
offsetInput++;
break;
case '*':
isAsterix = true;
while (i < pattern.Length &&
pattern[i] == '*')
{
i++;
}
if (i >= pattern.Length)
{
return true;
}
continue;
default:
if (offsetInput >= input.Length)
{
return false;
}
if ((ignoreCase
? char.ToLower(input[offsetInput])
: input[offsetInput])
!=
(ignoreCase
? char.ToLower(pattern[i])
: pattern[i]))
{
if (!isAsterix)
{
return false;
}
offsetInput++;
continue;
}
offsetInput++;
break;
}
i++;
}
if (i > input.Length)
{
return false;
}
public static bool IsMatch(string pattern, string input)
while (i < pattern.Length && pattern[i] == '*')
{
return IsMatch(pattern, input, true);
++i;
}
public static bool IsMatch(string pattern, string input, bool ignoreCase)
{
var offsetInput = 0;
var isAsterix = false;
int i = 0;
while (i < pattern.Length)
{
switch (pattern[i])
{
case '?':
isAsterix = false;
offsetInput++;
break;
case '*':
isAsterix = true;
while (i < pattern.Length &&
pattern[i] == '*')
{
i++;
}
if (i >= pattern.Length)
return true;
continue;
default:
if (offsetInput >= input.Length)
return false;
if ((ignoreCase
? char.ToLower(input[offsetInput])
: input[offsetInput])
!=
(ignoreCase
? char.ToLower(pattern[i])
: pattern[i]))
{
if (!isAsterix)
return false;
offsetInput++;
continue;
}
offsetInput++;
break;
}
i++;
}
if (i > input.Length)
return false;
while (i < pattern.Length && pattern[i] == '*')
++i;
return offsetInput == input.Length;
}
}
}
}

View File

@ -23,44 +23,38 @@
*
*/
namespace ASC.Common.Web
namespace ASC.Common.Web;
public abstract class AbstractHttpAsyncHandler // : IHttpAsyncHandler, IReadOnlySessionState
{
public abstract class AbstractHttpAsyncHandler // : IHttpAsyncHandler, IReadOnlySessionState
public bool IsReusable => false;
private Action<HttpContext> _processRequest;
private IPrincipal _principal;
private CultureInfo _culture;
public void ProcessRequest(HttpContext context)
{
private Action<Microsoft.AspNetCore.Http.HttpContext> processRequest;
private IPrincipal principal;
private CultureInfo culture;
public bool IsReusable
{
get { return false; }
}
public void ProcessRequest(Microsoft.AspNetCore.Http.HttpContext context)
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentPrincipal = principal;
//HttpContext.Current = context;
OnProcessRequest(context);
}
public IAsyncResult BeginProcessRequest(Microsoft.AspNetCore.Http.HttpContext context, AsyncCallback cb, object extraData)
{
culture = Thread.CurrentThread.CurrentCulture;
principal = Thread.CurrentPrincipal;
processRequest = ProcessRequest;
return processRequest.BeginInvoke(context, cb, extraData);
}
public void EndProcessRequest(IAsyncResult result)
{
processRequest.EndInvoke(result);
}
public abstract void OnProcessRequest(Microsoft.AspNetCore.Http.HttpContext context);
Thread.CurrentThread.CurrentCulture = _culture;
Thread.CurrentThread.CurrentUICulture = _culture;
Thread.CurrentPrincipal = _principal;
//HttpContext.Current = context;
OnProcessRequest(context);
}
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
_culture = Thread.CurrentThread.CurrentCulture;
_principal = Thread.CurrentPrincipal;
_processRequest = ProcessRequest;
return _processRequest.BeginInvoke(context, cb, extraData);
}
public void EndProcessRequest(IAsyncResult result)
{
_processRequest.EndInvoke(result);
}
public abstract void OnProcessRequest(HttpContext context);
}

View File

@ -23,71 +23,69 @@
*
*/
namespace ASC.Common.Web;
#region usings
#endregion
namespace ASC.Common.Web
public class DisposableHttpContext : IDisposable
{
public class DisposableHttpContext : IDisposable
private const string Key = "disposable.key";
public object this[string key]
{
private const string key = "disposable.key";
private readonly Microsoft.AspNetCore.Http.HttpContext ctx;
public DisposableHttpContext(Microsoft.AspNetCore.Http.HttpContext ctx)
get => Items.ContainsKey(key) ? Items[key] : null;
set
{
this.ctx = ctx ?? throw new ArgumentNullException();
}
public object this[string key]
{
get { return Items.ContainsKey(key) ? Items[key] : null; }
set
if (value == null)
{
if (value == null) throw new ArgumentNullException();
if (!(value is IDisposable)) throw new ArgumentException("Only IDisposable may be added!");
Items[key] = (IDisposable)value;
throw new ArgumentNullException();
}
}
private Dictionary<string, IDisposable> Items
{
get
if (!(value is IDisposable))
{
var table = (Dictionary<string, IDisposable>)ctx.Items[key];
if (table == null)
throw new ArgumentException("Only IDisposable may be added!");
}
Items[key] = (IDisposable)value;
}
}
private Dictionary<string, IDisposable> Items
{
get
{
var table = (Dictionary<string, IDisposable>)_context.Items[Key];
if (table == null)
{
table = new Dictionary<string, IDisposable>(1);
_context.Items.Add(Key, table);
}
return table;
}
}
private readonly HttpContext _context;
private bool _isDisposed;
public DisposableHttpContext(HttpContext ctx)
{
_context = ctx ?? throw new ArgumentNullException(nameof(ctx));
}
public void Dispose()
{
if (!_isDisposed)
{
foreach (var item in Items.Values)
{
try
{
table = new Dictionary<string, IDisposable>(1);
ctx.Items.Add(key, table);
item.Dispose();
}
return table;
catch { }
}
_isDisposed = true;
}
#region IDisposable Members
private bool _isDisposed;
public void Dispose()
{
if (!_isDisposed)
{
foreach (var item in Items.Values)
{
try
{
item.Dispose();
}
catch
{
}
}
_isDisposed = true;
}
}
#endregion
}
}

View File

@ -1,37 +1,36 @@
namespace ASC.Common.Web
namespace ASC.Common.Web;
public class HttpException : Exception
{
public class HttpException : Exception
public int StatusCode { get; }
public HttpException(int httpStatusCode)
{
public HttpException(int httpStatusCode)
{
StatusCode = httpStatusCode;
}
public HttpException(HttpStatusCode httpStatusCode)
{
StatusCode = (int)httpStatusCode;
}
public HttpException(int httpStatusCode, string message) : base(message)
{
StatusCode = httpStatusCode;
}
public HttpException(HttpStatusCode httpStatusCode, string message) : base(message)
{
StatusCode = (int)httpStatusCode;
}
public HttpException(int httpStatusCode, string message, Exception inner) : base(message, inner)
{
StatusCode = httpStatusCode;
}
public HttpException(HttpStatusCode httpStatusCode, string message, Exception inner) : base(message, inner)
{
StatusCode = (int)httpStatusCode;
}
public int StatusCode { get; }
StatusCode = httpStatusCode;
}
}
public HttpException(HttpStatusCode httpStatusCode)
{
StatusCode = (int)httpStatusCode;
}
public HttpException(int httpStatusCode, string message) : base(message)
{
StatusCode = httpStatusCode;
}
public HttpException(HttpStatusCode httpStatusCode, string message) : base(message)
{
StatusCode = (int)httpStatusCode;
}
public HttpException(int httpStatusCode, string message, Exception inner) : base(message, inner)
{
StatusCode = httpStatusCode;
}
public HttpException(HttpStatusCode httpStatusCode, string message, Exception inner) : base(message, inner)
{
StatusCode = (int)httpStatusCode;
}
}

View File

@ -1,19 +1,11 @@
namespace ASC.Common.Web
namespace ASC.Common.Web;
[Serializable]
public class ItemNotFoundException : HttpException
{
[Serializable]
public class ItemNotFoundException : HttpException
{
public ItemNotFoundException() : base(404, "Not found") { }
public ItemNotFoundException() : base(404, "Not found")
{
}
public ItemNotFoundException(string message) : base(404, message) { }
public ItemNotFoundException(string message) : base(404, message)
{
}
public ItemNotFoundException(string message, Exception inner) : base(404, message, inner)
{
}
}
public ItemNotFoundException(string message, Exception inner) : base(404, message, inner) { }
}

File diff suppressed because it is too large Load Diff

View File

@ -23,29 +23,27 @@
*
*/
namespace ASC.Common.Web
namespace ASC.Common.Web;
public class RouteCallInfo
{
public class RouteCallInfo
public int? Tid { get; set; }
public string Url { get; set; }
public string AttachmentUrl { get; set; }
public bool IsNewRequest { get; set; }
public string Method { get; set; }
public Dictionary<string, object> Params { get; set; }
public bool CleanupHtml { get; set; }
public RouteCallInfo()
{
public int? Tid { get; set; }
public string Url { get; set; }
public string AttachmentUrl { get; set; }
public bool IsNewRequest { get; set; }
public string Method { get; set; }
public Dictionary<string, object> Params { get; set; }
public bool CleanupHtml { get; set; }
public RouteCallInfo()
{
CleanupHtml = true;//Default
}
public override string ToString()
{
return string.Format("{0} {1} T:{2},{3}", Method.ToUpper(), Url, Tid, string.Join(",", Params.Select(x => string.Format("{0}={1}", x.Key, x.Value)).ToArray()));
}
CleanupHtml = true; //Default
}
}
public override string ToString()
{
return string.Format("{0} {1} T:{2},{3}", Method.ToUpper(), Url, Tid,
string.Join(",",
Params.Select(x => string.Format("{0}={1}", x.Key, x.Value)).ToArray()));
}
}

View File

@ -1,16 +1,19 @@
namespace ASC.Common.Web
namespace ASC.Common.Web;
public static class VirtualPathUtility
{
public static class VirtualPathUtility
public static string ToAbsolute(string virtualPath)
{
public static string ToAbsolute(string virtualPath)
if (string.IsNullOrEmpty(virtualPath))
{
if (string.IsNullOrEmpty(virtualPath))
return virtualPath;
if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute))
return virtualPath;
return "/" + virtualPath.TrimStart('~', '/');
return virtualPath;
}
if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute))
{
return virtualPath;
}
return "/" + virtualPath.TrimStart('~', '/');
}
}

View File

@ -40,7 +40,7 @@ namespace ASC.Core.Billing
Cache.Remove(TariffService.GetTariffCacheKey(i.TenantId));
Cache.Remove(TariffService.GetBillingUrlCacheKey(i.TenantId));
Cache.Remove(TariffService.GetBillingPaymentCacheKey(i.TenantId)); // clear all payments
}, CacheNotifyAction.Remove);
}, ASC.Common.Caching.CacheNotifyAction.Remove);
//TODO: Change code of WCF -> not supported in .NET standard/.Net Core
/*try
@ -297,7 +297,7 @@ namespace ASC.Core.Billing
public void ClearCache(int tenantId)
{
Notify.Publish(new TariffCacheItem { TenantId = tenantId }, CacheNotifyAction.Remove);
Notify.Publish(new TariffCacheItem { TenantId = tenantId }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public IEnumerable<PaymentInfo> GetPayments(int tenantId)

View File

@ -36,8 +36,8 @@ namespace ASC.Core.Caching
CacheNotify = cacheNotify;
Cache = cache;
cacheNotify.Subscribe((r) => UpdateCache(r, true), CacheNotifyAction.Remove);
cacheNotify.Subscribe((r) => UpdateCache(r, false), CacheNotifyAction.InsertOrUpdate);
cacheNotify.Subscribe((r) => UpdateCache(r, true), ASC.Common.Caching.CacheNotifyAction.Remove);
cacheNotify.Subscribe((r) => UpdateCache(r, false), ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
private void UpdateCache(AzRecord r, bool remove)
@ -102,14 +102,14 @@ namespace ASC.Core.Caching
public AzRecord SaveAce(int tenant, AzRecord r)
{
r = service.SaveAce(tenant, r);
cacheNotify.Publish(r, CacheNotifyAction.InsertOrUpdate);
cacheNotify.Publish(r, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
return r;
}
public void RemoveAce(int tenant, AzRecord r)
{
service.RemoveAce(tenant, r);
cacheNotify.Publish(r, CacheNotifyAction.Remove);
cacheNotify.Publish(r, ASC.Common.Caching.CacheNotifyAction.Remove);
}
}
}

View File

@ -62,7 +62,7 @@ namespace ASC.Core.Caching
{
Cache.Remove(i.Key);
}
}, CacheNotifyAction.Any);
}, ASC.Common.Caching.CacheNotifyAction.Any);
}
}
@ -142,7 +142,7 @@ namespace ASC.Core.Caching
public TenantQuota SaveTenantQuota(TenantQuota quota)
{
var q = Service.SaveTenantQuota(quota);
CacheNotify.Publish(new QuotaCacheItem { Key = QuotaServiceCache.KEY_QUOTA }, CacheNotifyAction.Any);
CacheNotify.Publish(new QuotaCacheItem { Key = QuotaServiceCache.KEY_QUOTA }, ASC.Common.Caching.CacheNotifyAction.Any);
return q;
}
@ -155,7 +155,7 @@ namespace ASC.Core.Caching
public void SetTenantQuotaRow(TenantQuotaRow row, bool exchange)
{
Service.SetTenantQuotaRow(row, exchange);
CacheNotify.Publish(new QuotaCacheItem { Key = GetKey(row.Tenant) }, CacheNotifyAction.InsertOrUpdate);
CacheNotify.Publish(new QuotaCacheItem { Key = GetKey(row.Tenant) }, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public IEnumerable<TenantQuotaRow> FindTenantQuotaRows(int tenantId)

View File

@ -48,7 +48,7 @@ namespace ASC.Core.Caching
store.SaveSubscription(s);
}
}
}, CacheNotifyAction.InsertOrUpdate);
}, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
notifyRecord.Subscribe((s) =>
{
@ -67,7 +67,7 @@ namespace ASC.Core.Caching
}
}
}
}, CacheNotifyAction.Remove);
}, ASC.Common.Caching.CacheNotifyAction.Remove);
notifyMethod.Subscribe((m) =>
{
@ -79,7 +79,7 @@ namespace ASC.Core.Caching
store.SetSubscriptionMethod(m);
}
}
}, CacheNotifyAction.Any);
}, ASC.Common.Caching.CacheNotifyAction.Any);
}
private SubsciptionsStore GetSubsciptionsStore(int tenant, string sourceId, string actionId)
@ -153,19 +153,19 @@ namespace ASC.Core.Caching
public void SaveSubscription(SubscriptionRecord s)
{
service.SaveSubscription(s);
notifyRecord.Publish(s, CacheNotifyAction.InsertOrUpdate);
notifyRecord.Publish(s, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public void RemoveSubscriptions(int tenant, string sourceId, string actionId)
{
service.RemoveSubscriptions(tenant, sourceId, actionId);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId }, CacheNotifyAction.Remove);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public void RemoveSubscriptions(int tenant, string sourceId, string actionId, string objectId)
{
service.RemoveSubscriptions(tenant, sourceId, actionId, objectId);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId, ObjectId = objectId }, CacheNotifyAction.Remove);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId, ObjectId = objectId }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public IEnumerable<SubscriptionMethod> GetSubscriptionMethods(int tenant, string sourceId, string actionId, string recipientId)
@ -180,7 +180,7 @@ namespace ASC.Core.Caching
public void SetSubscriptionMethod(SubscriptionMethod m)
{
service.SetSubscriptionMethod(m);
notifyMethod.Publish(m, CacheNotifyAction.Any);
notifyMethod.Publish(m, ASC.Common.Caching.CacheNotifyAction.Any);
}

View File

@ -50,12 +50,12 @@ namespace ASC.Core.Caching
var tenants = GetTenantStore();
tenants.Remove(t.TenantId);
tenants.Clear(coreBaseSettings);
}, CacheNotifyAction.InsertOrUpdate);
}, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
cacheNotifySettings.Subscribe((s) =>
{
Cache.Remove(s.Key);
}, CacheNotifyAction.Remove);
}, ASC.Common.Caching.CacheNotifyAction.Remove);
}
internal TenantStore GetTenantStore()
@ -267,14 +267,14 @@ namespace ASC.Core.Caching
public Tenant SaveTenant(CoreSettings coreSettings, Tenant tenant)
{
tenant = Service.SaveTenant(coreSettings, tenant);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = tenant.TenantId }, CacheNotifyAction.InsertOrUpdate);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = tenant.TenantId }, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
return tenant;
}
public void RemoveTenant(int id, bool auto = false)
{
Service.RemoveTenant(id, auto);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = id }, CacheNotifyAction.InsertOrUpdate);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = id }, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public IEnumerable<TenantVersion> GetTenantVersions()
@ -299,7 +299,7 @@ namespace ASC.Core.Caching
{
Service.SetTenantSettings(tenant, key, data);
var cacheKey = string.Format("settings/{0}/{1}", tenant, key);
CacheNotifySettings.Publish(new TenantSetting { Key = cacheKey }, CacheNotifyAction.Remove);
CacheNotifySettings.Publish(new TenantSetting { Key = cacheKey }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
}
}

View File

@ -54,12 +54,12 @@ namespace ASC.Core.Caching
CacheGroupCacheItem = cacheGroupCacheItem;
CacheUserGroupRefItem = cacheUserGroupRefItem;
cacheUserInfoItem.Subscribe((u) => InvalidateCache(u), CacheNotifyAction.Any);
cacheUserPhotoItem.Subscribe((p) => Cache.Remove(p.Key), CacheNotifyAction.Remove);
cacheGroupCacheItem.Subscribe((g) => InvalidateCache(), CacheNotifyAction.Any);
cacheUserInfoItem.Subscribe((u) => InvalidateCache(u), ASC.Common.Caching.CacheNotifyAction.Any);
cacheUserPhotoItem.Subscribe((p) => Cache.Remove(p.Key), ASC.Common.Caching.CacheNotifyAction.Remove);
cacheGroupCacheItem.Subscribe((g) => InvalidateCache(), ASC.Common.Caching.CacheNotifyAction.Any);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, true), CacheNotifyAction.Remove);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, false), CacheNotifyAction.InsertOrUpdate);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, true), ASC.Common.Caching.CacheNotifyAction.Remove);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, false), ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public void InvalidateCache()
@ -261,14 +261,14 @@ namespace ASC.Core.Caching
public UserInfo SaveUser(int tenant, UserInfo user)
{
user = Service.SaveUser(tenant, user);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Id = user.ID.ToString(), Tenant = tenant }, CacheNotifyAction.Any);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Id = user.ID.ToString(), Tenant = tenant }, ASC.Common.Caching.CacheNotifyAction.Any);
return user;
}
public void RemoveUser(int tenant, Guid id)
{
Service.RemoveUser(tenant, id);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Tenant = tenant, Id = id.ToString() }, CacheNotifyAction.Any);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Tenant = tenant, Id = id.ToString() }, ASC.Common.Caching.CacheNotifyAction.Any);
}
public byte[] GetUserPhoto(int tenant, Guid id)
@ -285,7 +285,7 @@ namespace ASC.Core.Caching
public void SetUserPhoto(int tenant, Guid id, byte[] photo)
{
Service.SetUserPhoto(tenant, id, photo);
CacheUserPhotoItem.Publish(new UserPhotoCacheItem { Key = UserServiceCache.GetUserPhotoCacheKey(tenant, id) }, CacheNotifyAction.Remove);
CacheUserPhotoItem.Publish(new UserPhotoCacheItem { Key = UserServiceCache.GetUserPhotoCacheKey(tenant, id) }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public DateTime GetUserPasswordStamp(int tenant, Guid id)
@ -316,14 +316,14 @@ namespace ASC.Core.Caching
public Group SaveGroup(int tenant, Group group)
{
group = Service.SaveGroup(tenant, group);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = group.Id.ToString() }, CacheNotifyAction.Any);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = group.Id.ToString() }, ASC.Common.Caching.CacheNotifyAction.Any);
return group;
}
public void RemoveGroup(int tenant, Guid id)
{
Service.RemoveGroup(tenant, id);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = id.ToString() }, CacheNotifyAction.Any);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = id.ToString() }, ASC.Common.Caching.CacheNotifyAction.Any);
}
@ -357,7 +357,7 @@ namespace ASC.Core.Caching
public UserGroupRef SaveUserGroupRef(int tenant, UserGroupRef r)
{
r = Service.SaveUserGroupRef(tenant, r);
CacheUserGroupRefItem.Publish(r, CacheNotifyAction.InsertOrUpdate);
CacheUserGroupRefItem.Publish(r, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
return r;
}
@ -366,7 +366,7 @@ namespace ASC.Core.Caching
Service.RemoveUserGroupRef(tenant, userId, groupId, refType);
var r = new UserGroupRef(userId, groupId, refType) { Tenant = tenant };
CacheUserGroupRefItem.Publish(r, CacheNotifyAction.Remove);
CacheUserGroupRefItem.Publish(r, ASC.Common.Caching.CacheNotifyAction.Remove);
}

View File

@ -170,7 +170,7 @@ namespace ASC.Core.Common.Configuration
this[providerProp.Key] = null;
}
Cache.Publish(new ConsumerCacheItem() { Name = this.Name }, CacheNotifyAction.Remove);
Cache.Publish(new ConsumerCacheItem() { Name = this.Name }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public bool Contains(KeyValuePair<string, string> item)

View File

@ -37,12 +37,12 @@ namespace ASC.Core.Data
{
Cache = cache;
Notify = notify;
Notify.Subscribe((i) => Cache.Remove(i.Key), CacheNotifyAction.Remove);
Notify.Subscribe((i) => Cache.Remove(i.Key), ASC.Common.Caching.CacheNotifyAction.Remove);
}
public void Remove(string key)
{
Notify.Publish(new SettingsCacheItem { Key = key }, CacheNotifyAction.Remove);
Notify.Publish(new SettingsCacheItem { Key = key }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
}

View File

@ -4,7 +4,8 @@
public class PostgreSqlMessagesContext : MessagesContext { }
public class MessagesContext : BaseDbContext
{
public DbSet<LoginEvents> LoginEvents { get; set; }
public DbSet<AuditEvent> AuditEvents { get; set; }
public DbSet<LoginEvent> LoginEvents { get; set; }
public DbSet<User> Users { get; set; }
protected override Dictionary<Provider, Func<BaseDbContext>> ProviderContext
@ -23,6 +24,7 @@
{
ModelBuilderWrapper
.From(modelBuilder, Provider)
.AddAuditEvent()
.AddLoginEvents()
.AddUser()
.AddDbFunction();

View File

@ -1,145 +1,145 @@
namespace ASC.Core.Common.EF.Model
{
public class AuditEvent : MessageEvent
{
public string Initiator { get; set; }
public string Target { get; set; }
}
public static class AuditEventExtension
{
public static ModelBuilderWrapper AddAuditEvent(this ModelBuilderWrapper modelBuilder)
{
modelBuilder
.Add(MySqlAddAuditEvent, Provider.MySql)
.Add(PgSqlAddAuditEvent, Provider.PostgreSql);
return modelBuilder;
}
public static void MySqlAddAuditEvent(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<AuditEvent>(entity =>
{
entity.ToTable("audit_events");
entity.HasIndex(e => new { e.TenantId, e.Date })
.HasDatabaseName("date");
entity
.Property(e => e.Id)
.HasColumnName("id")
.ValueGeneratedOnAdd();
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Date)
.HasColumnName("date")
.HasColumnType("datetime");
entity.Property(e => e.Description)
.HasColumnName("description")
.HasColumnType("varchar(20000)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Initiator)
.HasColumnName("initiator")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasColumnType("varchar(50)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasColumnType("varchar(300)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Target)
.HasColumnName("target")
.HasColumnType("text")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.HasColumnName("user_id")
.HasColumnType("char(38)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
});
}
public static void PgSqlAddAuditEvent(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<AuditEvent>(entity =>
{
entity.ToTable("audit_events", "onlyoffice");
entity.HasIndex(e => new { e.TenantId, e.Date })
.HasDatabaseName("date");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Date).HasColumnName("date");
entity.Property(e => e.Description)
.HasColumnName("description")
.HasMaxLength(20000)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Initiator)
.HasColumnName("initiator")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasMaxLength(50)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasMaxLength(300)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Target).HasColumnName("target");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.HasColumnName("user_id")
.HasMaxLength(38)
.IsFixedLength()
.HasDefaultValueSql("NULL");
});
}
}
}
namespace ASC.Core.Common.EF.Model
{
public class AuditEvent : MessageEvent
{
public string Initiator { get; set; }
public string Target { get; set; }
}
public static class AuditEventExtension
{
public static ModelBuilderWrapper AddAuditEvent(this ModelBuilderWrapper modelBuilder)
{
modelBuilder
.Add(MySqlAddAuditEvent, Provider.MySql)
.Add(PgSqlAddAuditEvent, Provider.PostgreSql);
return modelBuilder;
}
public static void MySqlAddAuditEvent(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<AuditEvent>(entity =>
{
entity.ToTable("audit_events");
entity.HasIndex(e => new { e.TenantId, e.Date })
.HasDatabaseName("date");
entity
.Property(e => e.Id)
.HasColumnName("id")
.ValueGeneratedOnAdd();
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Date)
.HasColumnName("date")
.HasColumnType("datetime");
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasColumnType("varchar(20000)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Initiator)
.HasColumnName("initiator")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasColumnType("varchar(50)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasColumnType("varchar(300)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Target)
.HasColumnName("target")
.HasColumnType("text")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.HasColumnName("user_id")
.HasColumnType("char(38)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
});
}
public static void PgSqlAddAuditEvent(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<AuditEvent>(entity =>
{
entity.ToTable("audit_events", "onlyoffice");
entity.HasIndex(e => new { e.TenantId, e.Date })
.HasDatabaseName("date");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Date).HasColumnName("date");
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasMaxLength(20000)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Initiator)
.HasColumnName("initiator")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasMaxLength(50)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasMaxLength(300)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Target).HasColumnName("target");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.HasColumnName("user_id")
.HasMaxLength(38)
.IsFixedLength()
.HasDefaultValueSql("NULL");
});
}
}
}

View File

@ -1,140 +1,141 @@
namespace ASC.Core.Common.EF.Model
{
public class LoginEvents : MessageEvent
{
public string Login { get; set; }
}
public static class LoginEventsExtension
{
public static ModelBuilderWrapper AddLoginEvents(this ModelBuilderWrapper modelBuilder)
{
modelBuilder
.Add(MySqlAddLoginEvents, Provider.MySql)
.Add(PgSqlAddLoginEvents, Provider.PostgreSql);
return modelBuilder;
}
public static void MySqlAddLoginEvents(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<LoginEvents>(entity =>
{
entity.ToTable("login_events");
entity.HasIndex(e => e.Date)
.HasDatabaseName("date");
entity.HasIndex(e => new { e.TenantId, e.UserId })
.HasDatabaseName("tenant_id");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Date)
.HasColumnName("date")
.HasColumnType("datetime");
entity.Property(e => e.Description)
.HasColumnName("description")
.HasColumnType("varchar(500)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasColumnType("varchar(50)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Login)
.HasColumnName("login")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasColumnType("varchar(300)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.IsRequired()
.HasColumnName("user_id")
.HasColumnType("char(38)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
});
}
public static void PgSqlAddLoginEvents(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<LoginEvents>(entity =>
{
entity.ToTable("login_events", "onlyoffice");
entity.HasIndex(e => e.Date)
.HasDatabaseName("date_login_events");
entity.HasIndex(e => new { e.UserId, e.TenantId })
.HasDatabaseName("tenant_id_login_events");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasMaxLength(200)
.HasDefaultValueSql("NULL::character varying");
entity.Property(e => e.Date).HasColumnName("date");
entity.Property(e => e.Description)
.HasColumnName("description")
.HasMaxLength(500)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasMaxLength(50)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Login)
.HasColumnName("login")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasMaxLength(300)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.IsRequired()
.HasColumnName("user_id")
.HasMaxLength(38)
.IsFixedLength();
});
}
}
}
namespace ASC.Core.Common.EF.Model
{
public class LoginEvent : MessageEvent
{
public string Login { get; set; }
}
public static class LoginEventsExtension
{
public static ModelBuilderWrapper AddLoginEvents(this ModelBuilderWrapper modelBuilder)
{
modelBuilder
.Add(MySqlAddLoginEvents, Provider.MySql)
.Add(PgSqlAddLoginEvents, Provider.PostgreSql);
return modelBuilder;
}
public static void MySqlAddLoginEvents(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<LoginEvent>(entity =>
{
entity.ToTable("login_events");
entity.HasIndex(e => e.Date)
.HasDatabaseName("date");
entity.HasIndex(e => new { e.TenantId, e.UserId })
.HasDatabaseName("tenant_id");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Date)
.HasColumnName("date")
.HasColumnType("datetime");
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasColumnType("varchar(500)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasColumnType("varchar(50)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Login)
.HasColumnName("login")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasColumnType("varchar(300)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasColumnType("varchar(200)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.IsRequired()
.HasColumnName("user_id")
.HasColumnType("char(38)")
.HasCharSet("utf8")
.UseCollation("utf8_general_ci");
});
}
public static void PgSqlAddLoginEvents(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<LoginEvent>(entity =>
{
entity.ToTable("login_events", "onlyoffice");
entity.HasIndex(e => e.Date)
.HasDatabaseName("date_login_events");
entity.HasIndex(e => new { e.UserId, e.TenantId })
.HasDatabaseName("tenant_id_login_events");
entity.Property(e => e.Id).HasColumnName("id");
entity.Property(e => e.Action).HasColumnName("action");
entity.Property(e => e.Browser)
.HasColumnName("browser")
.HasMaxLength(200)
.HasDefaultValueSql("NULL::character varying");
entity.Property(e => e.Date).HasColumnName("date");
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasMaxLength(500)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Ip)
.HasColumnName("ip")
.HasMaxLength(50)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Login)
.HasColumnName("login")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Page)
.HasColumnName("page")
.HasMaxLength(300)
.HasDefaultValueSql("NULL");
entity.Property(e => e.Platform)
.HasColumnName("platform")
.HasMaxLength(200)
.HasDefaultValueSql("NULL");
entity.Property(e => e.TenantId).HasColumnName("tenant_id");
entity.Property(e => e.UserId)
.IsRequired()
.HasColumnName("user_id")
.HasMaxLength(38)
.IsFixedLength();
});
}
}
}

View File

@ -11,6 +11,6 @@
public Guid UserId { get; set; }
public string Page { get; set; }
public int Action { get; set; }
public string Description { get; set; }
public string DescriptionRaw { get; set; }
}
}

View File

@ -23,6 +23,8 @@
*
*/
using CacheNotifyAction = ASC.Common.Caching.CacheNotifyAction;
namespace ASC.Core.Notify
{
[Scope]

View File

@ -50,7 +50,7 @@ namespace ASC.Core.Common.Notify
public void SendMessage(NotifyMessage m)
{
CacheMessage.Publish(m, CacheNotifyAction.Insert);
CacheMessage.Publish(m, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public void RegisterUser(string userId, int tenantId, string token)
@ -61,7 +61,7 @@ namespace ASC.Core.Common.Notify
UserId = userId,
TenantId = tenantId,
Token = token
}, CacheNotifyAction.Insert);
}, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public void CreateOrUpdateClient(int tenantId, string token, int tokenLifespan, string proxy)
@ -72,12 +72,12 @@ namespace ASC.Core.Common.Notify
Token = token,
TokenLifespan = tokenLifespan,
Proxy = proxy
}, CacheNotifyAction.Insert);
}, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public void DisableClient(int tenantId)
{
CacheDisableClient.Publish(new DisableClientProto() { TenantId = tenantId }, CacheNotifyAction.Insert);
CacheDisableClient.Publish(new DisableClientProto() { TenantId = tenantId }, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public string RegistrationToken(string userId, int tenantId)

View File

@ -65,7 +65,7 @@ namespace ASC.Data.Storage.Configuration
{
storageSettingsHelper.Clear(cdnSettings);
}
}, CacheNotifyAction.Remove);
}, Common.Caching.CacheNotifyAction.Remove);
}
}
}
@ -168,7 +168,7 @@ namespace ASC.Data.Storage.Configuration
var path = TenantPath.CreatePath(tenantId);
foreach (var module in StorageFactoryConfig.GetModuleList("", true))
{
Cache.Publish(new DataStoreCacheItem() { TenantId = path, Module = module }, CacheNotifyAction.Remove);
Cache.Publish(new DataStoreCacheItem() { TenantId = path, Module = module }, Common.Caching.CacheNotifyAction.Remove);
}
}

View File

@ -23,6 +23,8 @@
*
*/
using CacheNotifyAction = ASC.Common.Caching.CacheNotifyAction;
namespace ASC.Data.Storage.Encryption
{
[Scope]

Some files were not shown because too many files have changed in this diff Show More