规范代码

This commit is contained in:
cli 2025-04-21 10:17:40 +08:00
parent 01aeaebb0a
commit 02f2a2cafc
29 changed files with 604 additions and 689 deletions

View File

@ -1,33 +1,22 @@
using JiShe.CollectBus.IoTDB.Context;
using JiShe.CollectBus.IoTDB.Interface;
using JiShe.CollectBus.IoTDB.Options;
using JiShe.CollectBus.IoTDB.Provider;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity;
namespace JiShe.CollectBus.IoTDB
namespace JiShe.CollectBus.IoTDB;
/// <summary>
/// CollectBusIoTDBModule
/// </summary>
public class CollectBusIoTDbModule : AbpModule
{
public class CollectBusIoTDBModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
Configure<IoTDBOptions>(options =>
{
configuration.GetSection(nameof(IoTDBOptions)).Bind(options);
});
Configure<IoTDbOptions>(options => { configuration.GetSection(nameof(IoTDbOptions)).Bind(options); });
// 注册上下文为Scoped
context.Services.AddScoped<IoTDBRuntimeContext>();
// 注册Session工厂
context.Services.AddSingleton<IIoTDBSessionFactory, IoTDBSessionFactory>();
// 注册Provider
context.Services.AddScoped<IIoTDBProvider, IoTDBProvider>();
}
context.Services.AddScoped<IoTDbRuntimeContext>();
}
}

View File

@ -6,11 +6,11 @@ namespace JiShe.CollectBus.IoTDB.Context
/// <summary>
/// IoTDB SessionPool 运行时上下文
/// </summary>
public class IoTDBRuntimeContext
public class IoTDbRuntimeContext
{
private readonly bool _defaultValue;
public IoTDBRuntimeContext(IOptions<IoTDBOptions> options)
public IoTDbRuntimeContext(IOptions<IoTDbOptions> options)
{
_defaultValue = options.Value.UseTableSessionPoolByDefault;
UseTableSessionPool = _defaultValue;

View File

@ -7,7 +7,7 @@ namespace JiShe.CollectBus.IoTDB.Interface
/// <summary>
/// IoTDB数据源,数据库能同时存多个时序模型,但数据是完全隔离的,不能跨时序模型查询,通过连接字符串配置
/// </summary>
public interface IIoTDBProvider
public interface IIoTDbProvider
{
///// <summary>
///// 切换 SessionPool

View File

@ -3,8 +3,8 @@
/// <summary>
/// Session 工厂接口
/// </summary>
public interface IIoTDBSessionFactory:IDisposable
public interface IIoTDbSessionFactory:IDisposable
{
IIoTDBSessionPool GetSessionPool(bool useTableSession);
IIoTDbSessionPool GetSessionPool(bool useTableSession);
}
}

View File

@ -5,7 +5,7 @@ namespace JiShe.CollectBus.IoTDB.Interface
/// <summary>
/// Session 连接池
/// </summary>
public interface IIoTDBSessionPool : IDisposable
public interface IIoTDbSessionPool : IDisposable
{
/// <summary>
/// 打开连接池

View File

@ -3,7 +3,7 @@
/// <summary>
/// IOTDB配置
/// </summary>
public class IoTDBOptions
public class IoTDbOptions
{
/// <summary>
/// 数据库名称,表模型才有,树模型为空

View File

@ -9,26 +9,33 @@ using JiShe.CollectBus.IoTDB.Context;
using JiShe.CollectBus.IoTDB.Interface;
using JiShe.CollectBus.IoTDB.Options;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace JiShe.CollectBus.IoTDB.Provider
{
/// <summary>
/// IoTDB数据源
/// </summary>
public class IoTDBProvider : IIoTDBProvider
public class IoTDbProvider : IIoTDbProvider, IScopedDependency
{
private static readonly ConcurrentDictionary<Type, DeviceMetadata> _metadataCache = new();
private readonly ILogger<IoTDBProvider> _logger;
private readonly IIoTDBSessionFactory _sessionFactory;
private readonly IoTDBRuntimeContext _runtimeContext;
private static readonly ConcurrentDictionary<Type, DeviceMetadata> MetadataCache = new();
private readonly ILogger<IoTDbProvider> _logger;
private readonly IIoTDbSessionFactory _sessionFactory;
private readonly IoTDbRuntimeContext _runtimeContext;
private IIoTDBSessionPool CurrentSession =>
private IIoTDbSessionPool CurrentSession =>
_sessionFactory.GetSessionPool(_runtimeContext.UseTableSessionPool);
public IoTDBProvider(
ILogger<IoTDBProvider> logger,
IIoTDBSessionFactory sessionFactory,
IoTDBRuntimeContext runtimeContext)
/// <summary>
/// IoTDbProvider
/// </summary>
/// <param name="logger"></param>
/// <param name="sessionFactory"></param>
/// <param name="runtimeContext"></param>
public IoTDbProvider(
ILogger<IoTDbProvider> logger,
IIoTDbSessionFactory sessionFactory,
IoTDbRuntimeContext runtimeContext)
{
_logger = logger;
_sessionFactory = sessionFactory;
@ -396,7 +403,7 @@ namespace JiShe.CollectBus.IoTDB.Provider
var columns = CollectColumnMetadata(typeof(T));
var metadata = BuildDeviceMetadata(columns);
return _metadataCache.AddOrUpdate(
return MetadataCache.AddOrUpdate(
typeof(T),
addValueFactory: t => metadata, // 如果键不存在,用此值添加
updateValueFactory: (t, existingValue) =>

View File

@ -2,6 +2,7 @@
using JiShe.CollectBus.IoTDB.Interface;
using JiShe.CollectBus.IoTDB.Options;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
namespace JiShe.CollectBus.IoTDB.Provider
{
@ -9,25 +10,29 @@ namespace JiShe.CollectBus.IoTDB.Provider
/// <summary>
/// 实现带缓存的Session工厂
/// </summary>
public class IoTDBSessionFactory : IIoTDBSessionFactory
public class IoTDbSessionFactory : IIoTDbSessionFactory, ISingletonDependency
{
private readonly IoTDBOptions _options;
private readonly ConcurrentDictionary<bool, IIoTDBSessionPool> _pools = new();
private readonly IoTDbOptions _options;
private readonly ConcurrentDictionary<bool, IIoTDbSessionPool> _pools = new();
private bool _disposed;
public IoTDBSessionFactory(IOptions<IoTDBOptions> options)
/// <summary>
/// IoTDbSessionFactory
/// </summary>
/// <param name="options"></param>
public IoTDbSessionFactory(IOptions<IoTDbOptions> options)
{
_options = options.Value;
}
public IIoTDBSessionPool GetSessionPool(bool useTableSession)
public IIoTDbSessionPool GetSessionPool(bool useTableSession)
{
if (_disposed) throw new ObjectDisposedException(nameof(IoTDBSessionFactory));
if (_disposed) throw new ObjectDisposedException(nameof(IoTDbSessionFactory));
return _pools.GetOrAdd(useTableSession, key =>
{
var pool = key
? (IIoTDBSessionPool)new TableSessionPoolAdapter(_options)
? (IIoTDbSessionPool)new TableSessionPoolAdapter(_options)
: new SessionPoolAdapter(_options);
pool.OpenAsync().ConfigureAwait(false).GetAwaiter().GetResult(); ;

View File

@ -9,12 +9,16 @@ namespace JiShe.CollectBus.IoTDB.Provider
/// <summary>
/// 树模型连接池
/// </summary>
public class SessionPoolAdapter : IIoTDBSessionPool
public class SessionPoolAdapter : IIoTDbSessionPool
{
private readonly SessionPool _sessionPool;
private readonly IoTDBOptions _options;
private readonly IoTDbOptions _options;
public SessionPoolAdapter(IoTDBOptions options)
/// <summary>
/// SessionPoolAdapter
/// </summary>
/// <param name="options"></param>
public SessionPoolAdapter(IoTDbOptions options)
{
_options = options;
_sessionPool = new SessionPool.Builder()

View File

@ -9,12 +9,16 @@ namespace JiShe.CollectBus.IoTDB.Provider
/// <summary>
/// 表模型Session连接池
/// </summary>
public class TableSessionPoolAdapter : IIoTDBSessionPool
public class TableSessionPoolAdapter : IIoTDbSessionPool
{
private readonly TableSessionPool _sessionPool;
private readonly IoTDBOptions _options;
private readonly IoTDbOptions _options;
public TableSessionPoolAdapter(IoTDBOptions options)
/// <summary>
/// TableSessionPoolAdapter
/// </summary>
/// <param name="options"></param>
public TableSessionPoolAdapter(IoTDbOptions options)
{
_options = options;
_sessionPool = new TableSessionPool.Builder()

View File

@ -1,30 +1,24 @@
using Confluent.Kafka;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Confluent.Kafka.Admin;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;
namespace JiShe.CollectBus.Kafka.AdminClient
{
public class AdminClientService : IAdminClientService, IDisposable,ISingletonDependency
{
namespace JiShe.CollectBus.Kafka.AdminClient;
public class AdminClientService : IAdminClientService, IDisposable, ISingletonDependency
{
private readonly ILogger<AdminClientService> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="AdminClientService"/> class.
/// Initializes a new instance of the <see cref="AdminClientService" /> class.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="logger">The logger.</param>
/// <param name="configuration"></param>
/// <param name="logger"></param>
public AdminClientService(IConfiguration configuration, ILogger<AdminClientService> logger)
{
_logger = logger;
GetInstance(configuration);
Instance = GetInstance(configuration);
}
/// <summary>
@ -33,70 +27,17 @@ namespace JiShe.CollectBus.Kafka.AdminClient
/// <value>
/// The instance.
/// </value>
public IAdminClient Instance { get; set; } = default;
public IAdminClient Instance { get; set; }
/// <summary>
/// Gets the instance.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <returns></returns>
public IAdminClient GetInstance(IConfiguration configuration)
{
ArgumentNullException.ThrowIfNullOrWhiteSpace(configuration["Kafka:EnableAuthorization"]);
var enableAuthorization = bool.Parse(configuration["Kafka:EnableAuthorization"]!);
var adminClientConfig = new AdminClientConfig()
{
BootstrapServers = configuration["Kafka:BootstrapServers"],
};
if (enableAuthorization)
{
adminClientConfig.SecurityProtocol = SecurityProtocol.SaslPlaintext;
adminClientConfig.SaslMechanism = SaslMechanism.Plain;
adminClientConfig.SaslUsername = configuration["Kafka:SaslUserName"];
adminClientConfig.SaslPassword = configuration["Kafka:SaslPassword"];
}
Instance = new AdminClientBuilder(adminClientConfig).Build();
return Instance;
}
/// <summary>
/// Checks the topic asynchronous.
/// </summary>
/// <param name="topic">The topic.</param>
/// <returns></returns>
public async Task<bool> CheckTopicAsync(string topic)
{
var metadata = Instance.GetMetadata(TimeSpan.FromSeconds(5));
return await Task.FromResult(metadata.Topics.Exists(a => a.Topic == topic));
}
/// <summary>
/// 判断Kafka主题是否存在
/// </summary>
/// <param name="topic">主题名称</param>
/// <param name="numPartitions">副本数量不能高于Brokers数量</param>
/// <returns></returns>
public async Task<bool> CheckTopicAsync(string topic,int numPartitions)
{
var metadata = Instance.GetMetadata(TimeSpan.FromSeconds(5));
if(numPartitions > metadata.Brokers.Count)
{
throw new Exception($"{nameof(CheckTopicAsync)} 主题检查时,副本数量大于了节点数量。") ;
}
return await Task.FromResult(metadata.Topics.Exists(a => a.Topic == topic));
}
//// <summary>
/// 创建Kafka主题
/// </summary>
/// <param name="topic">主题名称</param>
/// <param name="numPartitions">主题分区数量</param>
/// <param name="replicationFactor">副本数量不能高于Brokers数量</param>
/// <param name="topic"></param>
/// <param name="numPartitions"></param>
/// <param name="replicationFactor"></param>
/// <returns></returns>
public async Task CreateTopicAsync(string topic, int numPartitions, short replicationFactor)
{
try
{
if (await CheckTopicAsync(topic)) return;
@ -114,10 +55,7 @@ namespace JiShe.CollectBus.Kafka.AdminClient
}
catch (CreateTopicsException e)
{
if (e.Results[0].Error.Code != ErrorCode.TopicAlreadyExists)
{
throw;
}
if (e.Results[0].Error.Code != ErrorCode.TopicAlreadyExists) throw;
}
}
@ -200,5 +138,53 @@ namespace JiShe.CollectBus.Kafka.AdminClient
{
Instance?.Dispose();
}
/// <summary>
/// Gets the instance.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <returns></returns>
public IAdminClient GetInstance(IConfiguration configuration)
{
ArgumentException.ThrowIfNullOrWhiteSpace(configuration["Kafka:EnableAuthorization"]);
var enableAuthorization = bool.Parse(configuration["Kafka:EnableAuthorization"]!);
var adminClientConfig = new AdminClientConfig
{
BootstrapServers = configuration["Kafka:BootstrapServers"]
};
if (enableAuthorization)
{
adminClientConfig.SecurityProtocol = SecurityProtocol.SaslPlaintext;
adminClientConfig.SaslMechanism = SaslMechanism.Plain;
adminClientConfig.SaslUsername = configuration["Kafka:SaslUserName"];
adminClientConfig.SaslPassword = configuration["Kafka:SaslPassword"];
}
return new AdminClientBuilder(adminClientConfig).Build();
}
/// <summary>
/// Checks the topic asynchronous.
/// </summary>
/// <param name="topic">The topic.</param>
/// <returns></returns>
public async Task<bool> CheckTopicAsync(string topic)
{
var metadata = Instance.GetMetadata(TimeSpan.FromSeconds(5));
return await Task.FromResult(metadata.Topics.Exists(a => a.Topic == topic));
}
/// <summary>
/// 判断Kafka主题是否存在
/// </summary>
/// <param name="topic">主题名称</param>
/// <param name="numPartitions">副本数量不能高于Brokers数量</param>
/// <returns></returns>
public async Task<bool> CheckTopicAsync(string topic, int numPartitions)
{
var metadata = Instance.GetMetadata(TimeSpan.FromSeconds(5));
if (numPartitions > metadata.Brokers.Count)
throw new Exception($"{nameof(CheckTopicAsync)} 主题检查时,副本数量大于了节点数量。");
return await Task.FromResult(metadata.Topics.Exists(a => a.Topic == topic));
}
}

View File

@ -1,14 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Attributes;
namespace JiShe.CollectBus.Kafka.Attributes
[AttributeUsage(AttributeTargets.Method)]
public class KafkaSubscribeAttribute : Attribute
{
[AttributeUsage(AttributeTargets.Method)]
public class KafkaSubscribeAttribute : Attribute
/// <summary>
/// 订阅主题
/// </summary>
/// <param name="batchTimeout"></param>
public KafkaSubscribeAttribute(string topic)
{
Topic = topic;
}
/// <summary>
/// 订阅主题
/// </summary>
public KafkaSubscribeAttribute(string topic, int partition)
{
Topic = topic;
Partition = partition;
}
/// <summary>
/// 订阅的主题
/// </summary>
@ -22,7 +34,7 @@ namespace JiShe.CollectBus.Kafka.Attributes
/// <summary>
/// 消费者组
/// </summary>
public string? GroupId { get; set; } = null;//"default"
public string? GroupId { get; set; } = null; //"default"
/// <summary>
/// 任务数(默认是多少个分区多少个任务)
@ -44,25 +56,5 @@ namespace JiShe.CollectBus.Kafka.Attributes
/// 批次超时时间
/// 格式:("00:05:00")
/// </summary>
public TimeSpan? BatchTimeout { get; set; }=null;
/// <summary>
/// 订阅主题
/// </summary>
/// <param name="batchTimeout"></param>
public KafkaSubscribeAttribute(string topic)
{
this.Topic = topic;
}
/// <summary>
/// 订阅主题
/// </summary>
public KafkaSubscribeAttribute(string topic, int partition)
{
this.Topic = topic;
this.Partition = partition;
}
}
public TimeSpan? BatchTimeout { get; set; } = null;
}

View File

@ -1,16 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Attributes;
namespace JiShe.CollectBus.Kafka.Attributes
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class TopicAttribute : Attribute
{
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class TopicAttribute: Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="TopicAttribute"/> class.
/// Initializes a new instance of the <see cref="TopicAttribute" /> class.
/// </summary>
/// <param name="name">The name.</param>
public TopicAttribute(string name = "Default")
@ -25,5 +19,4 @@ namespace JiShe.CollectBus.Kafka.Attributes
/// The name.
/// </value>
public string Name { get; set; }
}
}

View File

@ -13,15 +13,18 @@ namespace JiShe.CollectBus.Kafka.Consumer
public class ConsumerService : IConsumerService, IDisposable
{
private readonly ILogger<ConsumerService> _logger;
private readonly IConfiguration _configuration;
private readonly ConcurrentDictionary<Type, (object Consumer, CancellationTokenSource CTS)>
_consumerStore = new();
private readonly KafkaOptionConfig _kafkaOptionConfig;
private class KafkaConsumer<TKey, TValue> where TKey : notnull where TValue : class { }
public ConsumerService(IConfiguration configuration, ILogger<ConsumerService> logger, IOptions<KafkaOptionConfig> kafkaOptionConfig)
/// <summary>
/// ConsumerService
/// </summary>
/// <param name="logger"></param>
/// <param name="kafkaOptionConfig"></param>
public ConsumerService(ILogger<ConsumerService> logger, IOptions<KafkaOptionConfig> kafkaOptionConfig)
{
_configuration = configuration;
_logger = logger;
_kafkaOptionConfig = kafkaOptionConfig.Value;
}
@ -165,10 +168,10 @@ namespace JiShe.CollectBus.Kafka.Consumer
/// <summary>
/// 订阅消息
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="topics"></param>
/// <param name="messageHandler"></param>
/// <param name="groupId"></param>
/// <returns></returns>
public async Task SubscribeAsync<TValue>(string[] topics, Func<TValue, Task<bool>> messageHandler, string? groupId) where TValue : class
{
@ -387,7 +390,7 @@ namespace JiShe.CollectBus.Kafka.Consumer
/// <param name="consumeTimeout">消费等待时间</param>
public async Task SubscribeBatchAsync<TValue>(string topic, Func<List<TValue>, Task<bool>> messageBatchHandler, string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null, TimeSpan? consumeTimeout = null) where TValue : class
{
await SubscribeBatchAsync<TValue>(new[] { topic }, messageBatchHandler, groupId, batchSize, batchTimeout, consumeTimeout);
await SubscribeBatchAsync(new[] { topic }, messageBatchHandler, groupId, batchSize, batchTimeout, consumeTimeout);
}

View File

@ -1,15 +1,9 @@
using Confluent.Kafka;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Consumer;
namespace JiShe.CollectBus.Kafka.Consumer
public interface IConsumerService
{
public interface IConsumerService
{
Task SubscribeAsync<TKey, TValue>(string topic, Func<TKey, TValue, Task<bool>> messageHandler, string? groupId=null) where TKey : notnull where TValue : class;
Task SubscribeAsync<TKey, TValue>(string topic, Func<TKey, TValue, Task<bool>> messageHandler,
string? groupId = null) where TKey : notnull where TValue : class;
/// <summary>
/// 订阅消息
@ -18,9 +12,11 @@ namespace JiShe.CollectBus.Kafka.Consumer
/// <param name="topic"></param>
/// <param name="messageHandler"></param>
/// <returns></returns>
Task SubscribeAsync<TValue>(string topic, Func<TValue, Task<bool>> messageHandler, string? groupId = null) where TValue : class;
Task SubscribeAsync<TValue>(string topic, Func<TValue, Task<bool>> messageHandler, string? groupId = null)
where TValue : class;
Task SubscribeAsync<TKey, TValue>(string[] topics, Func<TKey, TValue, Task<bool>> messageHandler, string? groupId) where TKey : notnull where TValue : class;
Task SubscribeAsync<TKey, TValue>(string[] topics, Func<TKey, TValue, Task<bool>> messageHandler, string? groupId)
where TKey : notnull where TValue : class;
/// <summary>
@ -31,16 +27,24 @@ namespace JiShe.CollectBus.Kafka.Consumer
/// <param name="topics"></param>
/// <param name="messageHandler"></param>
/// <returns></returns>
Task SubscribeAsync<TValue>(string[] topics, Func<TValue, Task<bool>> messageHandler, string? groupId = null) where TValue : class;
Task SubscribeAsync<TValue>(string[] topics, Func<TValue, Task<bool>> messageHandler, string? groupId = null)
where TValue : class;
Task SubscribeBatchAsync<TKey, TValue>(string[] topics, Func<List<TValue>, Task<bool>> messageBatchHandler, string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null) where TKey : notnull where TValue : class;
Task SubscribeBatchAsync<TKey, TValue>(string[] topics, Func<List<TValue>, Task<bool>> messageBatchHandler,
string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null)
where TKey : notnull where TValue : class;
Task SubscribeBatchAsync<TKey, TValue>(string topic, Func<List<TValue>, Task<bool>> messageBatchHandler, string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null) where TKey : notnull where TValue : class;
Task SubscribeBatchAsync<TKey, TValue>(string topic, Func<List<TValue>, Task<bool>> messageBatchHandler,
string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null)
where TKey : notnull where TValue : class;
Task SubscribeBatchAsync<TValue>(string topic, Func<List<TValue>, Task<bool>> messageBatchHandler, string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null, TimeSpan? consumeTimeout = null) where TValue : class;
Task SubscribeBatchAsync<TValue>(string topic, Func<List<TValue>, Task<bool>> messageBatchHandler,
string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null, TimeSpan? consumeTimeout = null)
where TValue : class;
Task SubscribeBatchAsync<TValue>(string[] topics, Func<List<TValue>, Task<bool>> messageBatchHandler, string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null, TimeSpan? consumeTimeout = null) where TValue : class;
Task SubscribeBatchAsync<TValue>(string[] topics, Func<List<TValue>, Task<bool>> messageBatchHandler,
string? groupId = null, int batchSize = 100, TimeSpan? batchTimeout = null, TimeSpan? consumeTimeout = null)
where TValue : class;
void Unsubscribe<TKey, TValue>() where TKey : notnull where TValue : class;
}
}

View File

@ -1,17 +1,12 @@
using Confluent.Kafka;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Internal
namespace JiShe.CollectBus.Kafka.Internal;
/// <summary>
/// 消息头过滤器
/// </summary>
public class HeadersFilter : Dictionary<string, byte[]>
{
/// <summary>
/// 消息头过滤器
/// </summary>
public class HeadersFilter : Dictionary<string, byte[]>
{
/// <summary>
/// 判断Headers是否匹配
/// </summary>
@ -20,11 +15,8 @@ namespace JiShe.CollectBus.Kafka.Internal
public bool Match(Headers headers)
{
foreach (var kvp in this)
{
if (!headers.TryGetLastBytes(kvp.Key, out var value) || !value.SequenceEqual(kvp.Value))
return false;
}
return true;
}
}
}

View File

@ -1,18 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Internal;
namespace JiShe.CollectBus.Kafka.Internal
/// <summary>
/// Kafka订阅者
/// <para>
/// 订阅者需要继承此接口并需要依赖注入,并使用<see cref="KafkaSubscribeAttribute" />标记
/// </para>
/// </summary>
public interface IKafkaSubscribe
{
/// <summary>
/// Kafka订阅者
/// <para>
/// 订阅者需要继承此接口并需要依赖注入,并使用<see cref="KafkaSubscribeAttribute"/>标记
/// </para>
/// </summary>
public interface IKafkaSubscribe
{
}
}

View File

@ -1,13 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Internal;
namespace JiShe.CollectBus.Kafka.Internal
public interface ISubscribeAck
{
public interface ISubscribeAck
{
/// <summary>
/// 是否成功标记
/// </summary>
@ -17,5 +11,4 @@ namespace JiShe.CollectBus.Kafka.Internal
/// 消息
/// </summary>
string? Msg { get; set; }
}
}

View File

@ -1,14 +1,9 @@
using Confluent.Kafka;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Internal
namespace JiShe.CollectBus.Kafka.Internal;
public class KafkaOptionConfig
{
public class KafkaOptionConfig
{
/// <summary>
/// kafka地址
/// </summary>
@ -17,7 +12,7 @@ namespace JiShe.CollectBus.Kafka.Internal
/// <summary>
/// 服务器标识
/// </summary>
public string ServerTagName { get; set; }= "KafkaFilterKey";
public string ServerTagName { get; set; } = "KafkaFilterKey";
/// <summary>
/// kafka主题副本数量
@ -32,7 +27,7 @@ namespace JiShe.CollectBus.Kafka.Internal
/// <summary>
/// 是否开启过滤器
/// </summary>
public bool EnableFilter { get; set; }= true;
public bool EnableFilter { get; set; } = true;
/// <summary>
/// 是否开启认证
@ -47,7 +42,7 @@ namespace JiShe.CollectBus.Kafka.Internal
/// <summary>
/// 认证方式
/// </summary>
public SaslMechanism SaslMechanism { get; set; }= SaslMechanism.Plain;
public SaslMechanism SaslMechanism { get; set; } = SaslMechanism.Plain;
/// <summary>
/// 用户名
@ -63,6 +58,4 @@ namespace JiShe.CollectBus.Kafka.Internal
/// 首次采集时间
/// </summary>
public DateTime FirstCollectionTime { get; set; }
}
}

View File

@ -1,25 +1,19 @@
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Internal
namespace JiShe.CollectBus.Kafka.Internal;
/// <summary>
/// 反射辅助类
/// </summary>
public static class ReflectionHelper
{
/// <summary>
/// 反射辅助类
/// 集合类型
/// Item1参数类型
/// Item2集合元素类型
/// </summary>
public static class ReflectionHelper
{
/// <summary>
///集合类型
///Item1参数类型
///Item2集合元素类型
/// </summary>
public static Tuple<Type,Type?> GetParameterTypeInfo(this MethodInfo method, int parameterIndex=0)
public static Tuple<Type, Type?> GetParameterTypeInfo(this MethodInfo method, int parameterIndex = 0)
{
// 参数校验
if (method == null) throw new ArgumentNullException(nameof(method));
@ -27,18 +21,15 @@ namespace JiShe.CollectBus.Kafka.Internal
if (parameterIndex < 0 || parameterIndex >= parameters.Length)
throw new ArgumentOutOfRangeException(nameof(parameterIndex));
ParameterInfo param = parameters[parameterIndex];
Type paramType = param.ParameterType;
var param = parameters[parameterIndex];
var paramType = param.ParameterType;
Type? elementType = null;
// 判断是否是集合类型(排除字符串)
if (paramType != typeof(string) && IsEnumerableType(paramType))
{
elementType = GetEnumerableElementType(paramType);
}
return Tuple.Create(paramType, elementType);
}
/// <summary>
@ -50,7 +41,7 @@ namespace JiShe.CollectBus.Kafka.Internal
|| (type.IsGenericType && type.GetInterfaces()
.Any(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
|| type.GetInterfaces().Any(t => t == typeof(System.Collections.IEnumerable));
|| type.GetInterfaces().Any(t => t == typeof(IEnumerable));
}
/// <summary>
@ -81,20 +72,20 @@ namespace JiShe.CollectBus.Kafka.Internal
}
// <summary>
/// <summary>
/// 判断是否使用强转换
/// </summary>
/// <param name="targetType">目标类型</param>
/// <param name="targetType"></param>
/// <returns></returns>
public static bool IsConvertType(this Type targetType)
{
// 处理可空类型
Type underlyingType = Nullable.GetUnderlyingType(targetType) ?? targetType;
var underlyingType = Nullable.GetUnderlyingType(targetType) ?? targetType;
// 情况1值类型或基元类型如 int、DateTime
if (underlyingType.IsValueType || underlyingType.IsPrimitive)
return true;
// 情况2字符串类型直接赋值
else if (underlyingType == typeof(string))
if (underlyingType == typeof(string))
return true;
// 情况3枚举类型处理
@ -109,5 +100,4 @@ namespace JiShe.CollectBus.Kafka.Internal
//}
return false;
}
}
}

View File

@ -1,15 +1,7 @@
using Confluent.Kafka;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace JiShe.CollectBus.Kafka.Internal;
namespace JiShe.CollectBus.Kafka.Internal
public class SubscribeResult : ISubscribeAck
{
public class SubscribeResult: ISubscribeAck
{
/// <summary>
/// 是否成功
/// </summary>
@ -35,9 +27,7 @@ namespace JiShe.CollectBus.Kafka.Internal
/// <summary>
/// 失败
/// </summary>
/// <param name="code"></param>
/// <param name="msg"></param>
/// <param name="data"></param>
/// <returns></returns>
public SubscribeResult Fail(string? msg = null)
{
@ -45,11 +35,10 @@ namespace JiShe.CollectBus.Kafka.Internal
Ack = false;
return this;
}
}
public static partial class SubscribeAck
{
}
public static class SubscribeAck
{
/// <summary>
/// 成功
/// </summary>
@ -70,6 +59,4 @@ namespace JiShe.CollectBus.Kafka.Internal
{
return new SubscribeResult().Fail(msg);
}
}
}

View File

@ -8,26 +8,17 @@ using JiShe.CollectBus.Kafka.Consumer;
using JiShe.CollectBus.Kafka.Internal;
using JiShe.CollectBus.Kafka.Serialization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using YamlDotNet.Core.Tokens;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace JiShe.CollectBus.Kafka
{
public static class KafkaSubcribesExtensions
public static class KafkaSubscribeExtensions
{
public static void UseInitKafkaTopic(this IServiceProvider provider)
@ -36,7 +27,7 @@ namespace JiShe.CollectBus.Kafka
var kafkaAdminClient = provider.GetRequiredService<IAdminClientService>();
var kafkaOptions = provider.GetRequiredService<IOptions<KafkaOptionConfig>>();
List<string> topics = ProtocolConstExtensions.GetAllTopicNamesByIssued();
var topics = ProtocolConstExtensions.GetAllTopicNamesByIssued();
topics.AddRange(ProtocolConstExtensions.GetAllTopicNamesByReceived());
foreach (var item in topics)
@ -48,8 +39,6 @@ namespace JiShe.CollectBus.Kafka
/// <summary>
/// 添加Kafka订阅
/// </summary>
/// <param name="app"></param>
/// <param name="assembly"></param>
public static void UseKafkaSubscribe(this IServiceProvider provider)
{
var lifetime = provider.GetRequiredService<IHostApplicationLifetime>();
@ -57,8 +46,8 @@ namespace JiShe.CollectBus.Kafka
lifetime.ApplicationStarted.Register(() =>
{
var logger = provider.GetRequiredService<ILogger<CollectBusKafkaModule>>();
int threadCount = 0;
int topicCount = 0;
var threadCount = 0;
var topicCount = 0;
var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
if (string.IsNullOrWhiteSpace(assemblyPath))
{
@ -98,6 +87,9 @@ namespace JiShe.CollectBus.Kafka
});
}
/// <summary>
/// 添加Kafka订阅
/// </summary>
public static void UseKafkaSubscribersAsync(this IApplicationBuilder app, Assembly assembly)
{
var provider = app.ApplicationServices;
@ -134,8 +126,6 @@ namespace JiShe.CollectBus.Kafka
/// <summary>
/// 构建Kafka订阅
/// </summary>
/// <param name="subscribe"></param>
/// <param name="provider"></param>
private static Tuple<int, int> BuildKafkaSubscribe(object subscribe, IServiceProvider provider, ILogger<CollectBusKafkaModule> logger, KafkaOptionConfig kafkaOptionConfig)
{
var subscribedMethods = subscribe.GetType().GetMethods()
@ -169,11 +159,6 @@ namespace JiShe.CollectBus.Kafka
/// <summary>
/// 启动后台消费线程
/// </summary>
/// <param name="config"></param>
/// <param name="attr"></param>
/// <param name="method"></param>
/// <param name="consumerInstance"></param>
/// <returns></returns>
private static async Task StartConsumerAsync(IServiceProvider provider, KafkaSubscribeAttribute attr, MethodInfo method, object subscribe, ILogger<CollectBusKafkaModule> logger)
{
var consumerService = provider.GetRequiredService<IConsumerService>();
@ -225,10 +210,6 @@ namespace JiShe.CollectBus.Kafka
/// <summary>
/// 处理消息
/// </summary>
/// <param name="message"></param>
/// <param name="method"></param>
/// <param name="subscribe"></param>
/// <returns></returns>
private static async Task<bool> ProcessMessageAsync(List<dynamic> messages, MethodInfo method, object subscribe)
{
var parameters = method.GetParameters();
@ -351,9 +332,6 @@ namespace JiShe.CollectBus.Kafka
}
return false;
}
}

View File

@ -1,9 +1,4 @@
using Confluent.Kafka;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace JiShe.CollectBus.Kafka.Producer
{

View File

@ -23,6 +23,13 @@ namespace JiShe.CollectBus.Kafka.Producer
private readonly ConcurrentDictionary<Type, object> _producerCache = new();
private class KafkaProducer<TKey, TValue> where TKey : notnull where TValue : class { }
private readonly KafkaOptionConfig _kafkaOptionConfig;
/// <summary>
/// ProducerService
/// </summary>
/// <param name="configuration"></param>
/// <param name="logger"></param>
/// <param name="kafkaOptionConfig"></param>
public ProducerService(IConfiguration configuration,ILogger<ProducerService> logger, IOptions<KafkaOptionConfig> kafkaOptionConfig)
{
_configuration = configuration;

View File

@ -41,7 +41,7 @@ namespace JiShe.CollectBus;
typeof(CollectBusFreeRedisModule),
typeof(CollectBusFreeSqlModule),
typeof(CollectBusKafkaModule),
typeof(CollectBusIoTDBModule),
typeof(CollectBusIoTDbModule),
typeof(CollectBusCassandraModule)
)]
public class CollectBusApplicationModule : AbpModule

View File

@ -34,13 +34,13 @@ namespace JiShe.CollectBus.Samples;
public class SampleAppService : CollectBusAppService, ISampleAppService, IKafkaSubscribe
{
private readonly ILogger<SampleAppService> _logger;
private readonly IIoTDBProvider _iotDBProvider;
private readonly IoTDBRuntimeContext _dbContext;
private readonly IoTDBOptions _options;
private readonly IIoTDbProvider _iotDBProvider;
private readonly IoTDbRuntimeContext _dbContext;
private readonly IoTDbOptions _options;
private readonly IRedisDataCacheService _redisDataCacheService;
public SampleAppService(IIoTDBProvider iotDBProvider, IOptions<IoTDBOptions> options,
IoTDBRuntimeContext dbContext, ILogger<SampleAppService> logger, IRedisDataCacheService redisDataCacheService)
public SampleAppService(IIoTDbProvider iotDBProvider, IOptions<IoTDbOptions> options,
IoTDbRuntimeContext dbContext, ILogger<SampleAppService> logger, IRedisDataCacheService redisDataCacheService)
{
_iotDBProvider = iotDBProvider;
_options = options.Value;

View File

@ -37,7 +37,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
public abstract class BasicScheduledMeterReadingService : CollectBusAppService, IScheduledMeterReadingService
{
private readonly ILogger<BasicScheduledMeterReadingService> _logger;
private readonly IIoTDBProvider _dbProvider;
private readonly IIoTDbProvider _dbProvider;
private readonly IMeterReadingRecordRepository _meterReadingRecordRepository;
private readonly IProducerService _producerService;
private readonly IRedisDataCacheService _redisDataCacheService;
@ -48,7 +48,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
IMeterReadingRecordRepository meterReadingRecordRepository,
IProducerService producerService,
IRedisDataCacheService redisDataCacheService,
IIoTDBProvider dbProvider,
IIoTDbProvider dbProvider,
IOptions<KafkaOptionConfig> kafkaOptions)
{
_logger = logger;

View File

@ -37,7 +37,7 @@ namespace JiShe.CollectBus.ScheduledMeterReading
string serverTagName = string.Empty;
public EnergySystemScheduledMeterReadingService(
ILogger<EnergySystemScheduledMeterReadingService> logger,
IIoTDBProvider dbProvider,
IIoTDbProvider dbProvider,
IMeterReadingRecordRepository meterReadingRecordRepository,
IOptions<KafkaOptionConfig> kafkaOptions,
IProducerService producerService,

View File

@ -31,7 +31,7 @@ namespace JiShe.CollectBus.Subscribers
private readonly IRepository<MessageReceivedLogin, Guid> _messageReceivedLoginEventRepository;
private readonly IRepository<MessageReceivedHeartbeat, Guid> _messageReceivedHeartbeatEventRepository;
private readonly IMeterReadingRecordRepository _meterReadingRecordsRepository;
private readonly IIoTDBProvider _dbProvider;
private readonly IIoTDbProvider _dbProvider;
/// <summary>
/// Initializes a new instance of the <see cref="SubscriberAppService"/> class.
@ -47,7 +47,7 @@ namespace JiShe.CollectBus.Subscribers
IServiceProvider serviceProvider,
IRepository<MessageReceivedLogin, Guid> messageReceivedLoginEventRepository,
IRepository<MessageReceivedHeartbeat, Guid> messageReceivedHeartbeatEventRepository,
IIoTDBProvider dbProvider,
IIoTDbProvider dbProvider,
IMeterReadingRecordRepository meterReadingRecordsRepository)
{
_logger = logger;