add ValueBinder

This commit is contained in:
陈国伟 2021-11-23 10:02:21 +08:00
parent 8cf0dc53ef
commit 2d9f505634
6 changed files with 98 additions and 23 deletions

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Net;
namespace FastGithub.Configuration namespace FastGithub.Configuration
{ {
@ -26,7 +27,7 @@ namespace FastGithub.Configuration
/// <summary> /// <summary>
/// 使用的ip地址 /// 使用的ip地址
/// </summary> /// </summary>
public string? IPAddress { get; init; } public IPAddress? IPAddress { get; init; }
/// <summary> /// <summary>
/// 请求超时时长 /// 请求超时时长
@ -59,6 +60,6 @@ namespace FastGithub.Configuration
return Configuration.TlsSniPattern.Domain; return Configuration.TlsSniPattern.Domain;
} }
return new TlsSniPattern(this.TlsSniPattern); return new TlsSniPattern(this.TlsSniPattern);
} }
} }
} }

View File

@ -35,7 +35,7 @@ namespace FastGithub.Configuration
var opt = options.CurrentValue; var opt = options.CurrentValue;
this.HttpProxyPort = opt.HttpProxyPort; this.HttpProxyPort = opt.HttpProxyPort;
this.FallbackDns = ConvertToIPEndPoints(opt.FallbackDns).ToArray(); this.FallbackDns = opt.FallbackDns;
this.domainConfigs = ConvertDomainConfigs(opt.DomainConfigs); this.domainConfigs = ConvertDomainConfigs(opt.DomainConfigs);
this.domainConfigCache = new ConcurrentDictionary<string, DomainConfig?>(); this.domainConfigCache = new ConcurrentDictionary<string, DomainConfig?>();
@ -49,27 +49,11 @@ namespace FastGithub.Configuration
private void Update(FastGithubOptions options) private void Update(FastGithubOptions options)
{ {
this.HttpProxyPort = options.HttpProxyPort; this.HttpProxyPort = options.HttpProxyPort;
this.FallbackDns = ConvertToIPEndPoints(options.FallbackDns).ToArray(); this.FallbackDns = options.FallbackDns;
this.domainConfigs = ConvertDomainConfigs(options.DomainConfigs); this.domainConfigs = ConvertDomainConfigs(options.DomainConfigs);
this.domainConfigCache = new ConcurrentDictionary<string, DomainConfig?>(); this.domainConfigCache = new ConcurrentDictionary<string, DomainConfig?>();
} }
/// <summary>
/// 转换为IPEndPoint
/// </summary>
/// <param name="ipEndPoints"></param>
/// <returns></returns>
private static IEnumerable<IPEndPoint> ConvertToIPEndPoints(IEnumerable<string> ipEndPoints)
{
foreach (var item in ipEndPoints)
{
if (IPEndPoint.TryParse(item, out var endPoint))
{
yield return endPoint;
}
}
}
/// <summary> /// <summary>
/// 配置转换 /// 配置转换
/// </summary> /// </summary>

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net;
namespace FastGithub.Configuration namespace FastGithub.Configuration
{ {
@ -16,7 +17,7 @@ namespace FastGithub.Configuration
/// <summary> /// <summary>
/// 回退的dns /// 回退的dns
/// </summary> /// </summary>
public string[] FallbackDns { get; set; } = Array.Empty<string>(); public IPEndPoint[] FallbackDns { get; set; } = Array.Empty<IPEndPoint>();
/// <summary> /// <summary>
/// 代理的域名配置 /// 代理的域名配置

View File

@ -2,6 +2,7 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Net;
namespace FastGithub namespace FastGithub
{ {
@ -17,6 +18,9 @@ namespace FastGithub
/// <returns></returns> /// <returns></returns>
public static IServiceCollection AddConfiguration(this IServiceCollection services) public static IServiceCollection AddConfiguration(this IServiceCollection services)
{ {
ValueBinder.Bind(val => IPAddress.Parse(val), val => val?.ToString());
ValueBinder.Bind(val => IPEndPoint.Parse(val), val => val?.ToString());
services.TryAddSingleton<FastGithubConfig>(); services.TryAddSingleton<FastGithubConfig>();
return services; return services;
} }

View File

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
namespace FastGithub.Configuration
{
/// <summary>
/// 配置值绑定器
/// </summary>
static class ValueBinder
{
private static readonly Dictionary<Type, Binder> binders = new();
/// <summary>
/// 绑定转换器到指定类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="reader"></param>
/// <param name="writer"></param>
public static void Bind<T>(Func<string, T?> reader, Func<T?, string?> writer)
{
binders[typeof(T)] = new Binder<T>(reader, writer);
var converterType = typeof(TypeConverter<>).MakeGenericType(typeof(T));
if (TypeDescriptor.GetConverter(typeof(T)).GetType() != converterType)
{
TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(converterType));
}
}
private abstract class Binder
{
public abstract object? Read(string value);
public abstract string? Write(object? value);
}
private class Binder<T> : Binder
{
private readonly Func<string, T?> reader;
private readonly Func<T?, string?> writer;
public Binder(Func<string, T?> reader, Func<T?, string?> writer)
{
this.reader = reader;
this.writer = writer;
}
public override object? Read(string value)
{
return this.reader(value);
}
public override string? Write(object? value)
{
return this.writer((T?)value);
}
}
private class TypeConverter<T> : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
return value is string stringVal && binders.TryGetValue(typeof(T), out var binder)
? binder.Read(stringVal)
: base.ConvertFrom(context, culture, value);
}
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
{
return destinationType == typeof(T) && binders.TryGetValue(destinationType, out var binder)
? binder.Write(value)
: base.ConvertTo(context, culture, value, destinationType);
}
}
}
}

View File

@ -181,9 +181,9 @@ namespace FastGithub.Http
} }
else else
{ {
if (IPAddress.TryParse(this.domainConfig.IPAddress, out address)) if (this.domainConfig.IPAddress != null)
{ {
yield return new IPEndPoint(address, dnsEndPoint.Port); yield return new IPEndPoint(this.domainConfig.IPAddress, dnsEndPoint.Port);
} }
await foreach (var item in this.domainResolver.ResolveAllAsync(dnsEndPoint, cancellationToken)) await foreach (var item in this.domainResolver.ResolveAllAsync(dnsEndPoint, cancellationToken))