using System.Text; using Hangfire; using Hangfire.Redis.StackExchange; using JiShe.CollectBus.Host.Hangfire; using JiShe.CollectBus.Host.Swaggers; using MassTransit; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.DataProtection; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using StackExchange.Redis; using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.Auditing; using Volo.Abp.BackgroundJobs; using Volo.Abp.Caching; using Volo.Abp.Modularity; using TouchSocket.Core; using TouchSocket.Sockets; using JiShe.CollectBus.Plugins; using JiShe.CollectBus.Consumers; using JiShe.CollectBus.MessageReceiveds; using JiShe.CollectBus.Protocol.Contracts; namespace JiShe.CollectBus.Host { public partial class CollectBusHostModule { /// /// Configures the hangfire. /// /// The context. private void ConfigureHangfire(ServiceConfigurationContext context) { var redisStorageOptions = new RedisStorageOptions() { Db = context.Services.GetConfiguration().GetValue("Redis:HangfireDB") }; Configure(options => { options.IsJobExecutionEnabled = true; }); context.Services.AddHangfire(config => { config.UseRedisStorage( context.Services.GetConfiguration().GetValue("Redis:Configuration"), redisStorageOptions) .WithJobExpirationTimeout(TimeSpan.FromDays(7)); var delaysInSeconds = new[] { 10, 60, 60 * 3 }; // 重试时间间隔 const int Attempts = 3; // 重试次数 config.UseFilter(new AutomaticRetryAttribute() { Attempts = Attempts, DelaysInSeconds = delaysInSeconds }); //config.UseFilter(new AutoDeleteAfterSuccessAttribute(TimeSpan.FromDays(7))); config.UseFilter(new JobRetryLastFilter(Attempts)); }); context.Services.AddHangfireServer(); } /// /// Configures the JWT authentication. /// /// The context. /// The configuration. private void ConfigureJwtAuthentication(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters() { // 是否开启签名认证 ValidateIssuerSigningKey = true, ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ClockSkew = TimeSpan.Zero, ValidIssuer = configuration["Jwt:Issuer"], ValidAudience = configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.ASCII.GetBytes(configuration["Jwt:SecurityKey"])) }; options.Events = new JwtBearerEvents { OnMessageReceived = currentContext => { var path = currentContext.HttpContext.Request.Path; if (path.StartsWithSegments("/login")) { return Task.CompletedTask; } var accessToken = string.Empty; if (currentContext.HttpContext.Request.Headers.ContainsKey("Authorization")) { accessToken = currentContext.HttpContext.Request.Headers["Authorization"]; if (!string.IsNullOrWhiteSpace(accessToken)) { accessToken = accessToken.Split(" ").LastOrDefault(); } } if (string.IsNullOrWhiteSpace(accessToken)) { accessToken = currentContext.Request.Query["access_token"].FirstOrDefault(); } if (string.IsNullOrWhiteSpace(accessToken)) { accessToken = currentContext.Request.Cookies[@CollectBusHostConst.DefaultCookieName]; } currentContext.Token = accessToken; currentContext.Request.Headers.Remove("Authorization"); currentContext.Request.Headers.Add("Authorization", $"Bearer {accessToken}"); return Task.CompletedTask; } }; }); } /// /// Configures the cache. /// /// The context. private void ConfigureCache(ServiceConfigurationContext context) { Configure( options => { options.KeyPrefix = "CollectBus:"; }); var configuration = context.Services.GetConfiguration(); var redis = ConnectionMultiplexer.Connect($"{configuration.GetValue("Redis:Configuration")},defaultdatabase={configuration.GetValue("Redis:DefaultDB")}"); context.Services .AddDataProtection() .PersistKeysToStackExchangeRedis(redis, "CollectBus-Protection-Keys"); } /// /// Configures the swagger services. /// /// The context. /// The configuration. private void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddSwaggerGen( options => { configuration.GetSection("SwaggerConfig").Get>()?.ForEach(group => { options.SwaggerDoc(group.GroupName, new OpenApiInfo { Title = group.Title, Version = group.Version }); }); options.DocInclusionPredicate((docName, apiDes) => { if (docName == "Basic" && string.IsNullOrWhiteSpace(apiDes.GroupName)) return true; return docName == apiDes.GroupName; }); options.EnableAnnotations(); options.DocumentFilter(); options.SchemaFilter(); var xmlPaths = Directory.GetFiles(AppContext.BaseDirectory, "*.xml") .Where(a => a.EndsWith("Application.xml") || a.EndsWith("Application.Contracts.xml") || a.EndsWith("httpApi.xml") || a.EndsWith("Host.xml")) .Distinct() .ToList(); foreach (var xml in xmlPaths) options.IncludeXmlComments(xml, true); }); } /// /// Configures the audit log. /// /// The context. private void ConfigureAuditLog(ServiceConfigurationContext context) { Configure ( options => { options.IsEnabled = true; options.EntityHistorySelectors.AddAllEntities(); options.ApplicationName = "JiShe.CollectBus"; } ); Configure( options => { options.IgnoredUrls.Add("/AuditLogs/page"); options.IgnoredUrls.Add("/hangfire/stats"); options.IgnoredUrls.Add("/hangfire/recurring/trigger"); options.IgnoredUrls.Add("/cap"); options.IgnoredUrls.Add("/"); }); } /// /// Configures the custom. /// /// The context. /// The configuration. private void ConfigureCustom(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddSingleton(); context.Services.AddHealthChecks(); } /// /// Configures the network. /// /// The context. /// The configuration. public void ConfigureNetwork(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddTcpService(config => { config.SetListenIPHosts(int.Parse(configuration["TCP:ClientPort"] ?? "10500")) //.SetTcpDataHandlingAdapter(()=>new StandardFixedHeaderDataHandlingAdapter()) //.SetGetDefaultNewId(() => Guid.NewGuid().ToString())//定义ClinetId的生成策略 .ConfigurePlugins(a => { a.Add(); a.Add(); a.Add(); }); }); context.Services.AddUdpSession(config => { config.SetBindIPHost(int.Parse(configuration["UDP:ClientPort"] ?? "10500")) .ConfigurePlugins(a => { a.Add(); a.Add(); }) .UseBroadcast() .SetUdpDataHandlingAdapter(() => new NormalUdpDataHandlingAdapter()); }); } /// /// Configures the cap. /// /// The context. /// The configuration. public void ConfigureCap(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddCap(x => { x.DefaultGroupName = ProtocolConst.SubscriberGroup; var connectionStr = configuration.GetConnectionString(CollectBusDbProperties.MongoDbConnectionStringName); x.UseMongoDB(connectionStr); //MongoDB 4.0+ cluster var kafka = configuration.GetConnectionString("Kafka"); x.UseKafka(option => { option.Servers = kafka; }); x.UseDashboard(); x.FailedRetryInterval = 10; x.FailedRetryCount = 5; }); } /// /// Configures the mass transit. /// /// The context. /// The configuration. public void ConfigureMassTransit(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddMassTransit(x => { x.UsingInMemory(); x.AddConfigureEndpointsCallback((c, name, cfg) => { cfg.UseDelayedRedelivery(r => r.Intervals(TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(30))); cfg.UseMessageRetry(r => r.Immediate(5)); cfg.UseInMemoryOutbox(c); }); x.AddRider(rider => { rider.AddConsumer(); rider.AddConsumer(); rider.AddConsumer(); rider.AddConsumer(cfg => { cfg.Options(options => options .SetMessageLimit(100) .SetTimeLimit(s: 1) .SetTimeLimitStart(BatchTimeLimitStart.FromLast) .SetConcurrencyLimit(10)); }); rider.UsingKafka((c, cfg) => { cfg.Host(configuration.GetConnectionString("Kafka")); cfg.TopicEndpoint(ProtocolConst.SubscriberReceivedHeartbeatEventName, ProtocolConst.SubscriberGroup, configurator => { configurator.ConfigureConsumer(c); configurator.ConfigureConsumeTopology = false; }); cfg.TopicEndpoint(ProtocolConst.SubscriberReceivedLoginEventName, ProtocolConst.SubscriberGroup, configurator => { configurator.ConfigureConsumer(c); configurator.ConfigureConsumeTopology = false; }); cfg.TopicEndpoint(ProtocolConst.SubscriberReceivedEventName, ProtocolConst.SubscriberGroup, configurator => { configurator.ConfigureConsumer(c); configurator.ConfigureConsumeTopology = false; }); cfg.TopicEndpoint(ProtocolConst.SubscriberIssuedEventName, ProtocolConst.SubscriberGroup, configurator => { configurator.ConfigureConsumer(c); configurator.ConfigureConsumeTopology = false; }); }); }); }); } } }