diff --git a/OpenAuth.Repository/Domain/LasaTask.cs b/OpenAuth.Repository/Domain/LasaTask.cs index 873a81d..5e27590 100644 --- a/OpenAuth.Repository/Domain/LasaTask.cs +++ b/OpenAuth.Repository/Domain/LasaTask.cs @@ -57,6 +57,15 @@ namespace OpenAuth.Repository.Domain /// AI巡检 /// public string AIInspection { get; set; } + + /// + /// 状态 + /// + public int Status { get; set; } + /// + /// 周期公式 + /// + public string PeriodicFormula { get; set; } public long CreateId { get; set; } public DateTime? CreateTime { get; set; } diff --git a/OpenAuth.WebApi/Controllers/ServiceControllers/ManageController.cs b/OpenAuth.WebApi/Controllers/ServiceControllers/ManageController.cs index 5fc52c4..e43f507 100644 --- a/OpenAuth.WebApi/Controllers/ServiceControllers/ManageController.cs +++ b/OpenAuth.WebApi/Controllers/ServiceControllers/ManageController.cs @@ -1,5 +1,7 @@ -using Infrastructure; +using System.Text; +using Infrastructure; using Infrastructure.Extensions; +using Infrastructure.Helpers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using OpenAuth.App.ServiceApp; @@ -15,11 +17,16 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers public class ManageController : ControllerBase { private readonly ManageApp _app; - public ManageController(ManageApp app) + private readonly MqttClientManager _mqttClientManager; + + public ManageController(ManageApp app, MqttClientManager mqttClientManager) { _app = app; + _mqttClientManager = mqttClientManager; } + #region 机场管理 + /// /// 获取机场列表 /// @@ -40,11 +47,14 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers result.Code = 500; result.Message = ex.Message; } + return result; } + #endregion #region 无人机管理 + /// /// 获取无人机列表 /// @@ -65,11 +75,14 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers result.Code = 500; result.Message = ex.Message; } + return result; } + #endregion #region 任务管理 + /// /// 获取任务列表 /// @@ -90,6 +103,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers result.Code = 500; result.Message = ex.Message; } + return result; } @@ -102,6 +116,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.AddTask(info); } + /// /// 编辑任务 /// @@ -111,6 +126,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.EditTask(info); } + /// /// 删除任务 /// @@ -120,9 +136,11 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.DeleteTask(id); } + #endregion #region 航线管理 + /// /// 获取航线列表 /// @@ -143,6 +161,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers result.Code = 500; result.Message = ex.Message; } + return result; } @@ -155,6 +174,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.AddAirLine(info); } + /// /// 编辑航线 /// @@ -164,6 +184,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.EditAirLine(info); } + /// /// 删除航线 /// @@ -173,6 +194,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.DeleteAirLine(id); } + /// /// 上传航线文件 /// @@ -197,6 +219,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers return Ok(new { message = "上传成功", path = filePath }); } + [HttpPost("uploadwpmlfile")] [AllowAnonymous] public async Task UploadWpmlFile(IFormFile xmlFile, string id) @@ -217,9 +240,11 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers return Ok(new { message = "上传成功", path = filePath }); } + #endregion #region 项目管理 + /// /// 获取项目列表 /// @@ -238,6 +263,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers result.Code = 500; result.Message = ex.Message; } + return result; } @@ -250,6 +276,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.AddWorkspace(info); } + /// /// 编辑项目 /// @@ -259,6 +286,7 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.EditWorkspace(info); } + /// /// 删除项目 /// @@ -268,6 +296,22 @@ namespace OpenAuth.WebApi.Controllers.ServiceControllers { return await _app.DeleteWorkspace(id); } + #endregion + + // 航线任务在云端的 共享查看、下发执行、取消以及进度上报等功能。 + + [HttpGet] + [AllowAnonymous] + public async Task Test() + { + await _mqttClientManager.SubscribeAsync("thing/product/8UUXN5400A079H/osd", async (args) => + { + var payload = args.ApplicationMessage.Payload; + var message = Encoding.UTF8.GetString(payload); + Console.WriteLine($"收到主题 [{args.ApplicationMessage.Topic}] 的消息: {message}"); + await Task.CompletedTask; // 可选:实际逻辑中可执行更多异步操作 + }); + } } -} +} \ No newline at end of file diff --git a/OpenAuth.WebApi/MqttClientManager.cs b/OpenAuth.WebApi/MqttClientManager.cs new file mode 100644 index 0000000..6dc5778 --- /dev/null +++ b/OpenAuth.WebApi/MqttClientManager.cs @@ -0,0 +1,68 @@ +using MQTTnet; +using MQTTnet.Client; +using MQTTnet.Protocol; + +namespace OpenAuth.WebApi; + +public class MqttClientManager +{ + private IMqttClient _mqttClient; + + public MqttClientManager() + { + var mqttFactory = new MqttFactory(); + _mqttClient = mqttFactory.CreateMqttClient(); + // 创建配置构建器 + var builder = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) + .AddJsonFile( + $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"}.json", + optional: true) + .AddEnvironmentVariables(); + // 构建配置 + var configuration = builder.Build(); + // 读取连接字符串 + var serverIp = configuration["MQTT:Server"]; + var port = configuration["MQTT:Port"]; + var username = configuration["MQTT:UserName"]; + var password = configuration["MQTT:Password"]; + ConnectAsync(serverIp, int.Parse(port), username, password).Wait(); + } + + /// + /// + /// + /// + /// + /// + /// + public async Task ConnectAsync(string server, int port, string username = null, string password = null) + { + var mqttClientOptions = new MqttClientOptionsBuilder() + .WithClientId("client001") + .WithTcpServer(server, port) + .WithCredentials(username, password) + .Build(); + + await _mqttClient.ConnectAsync(mqttClientOptions, CancellationToken.None); + } + + public async Task SubscribeAsync(string topic, + Func handler) + { + await _mqttClient.SubscribeAsync(topic, MqttQualityOfServiceLevel.AtLeastOnce, CancellationToken.None); + _mqttClient.ApplicationMessageReceivedAsync += handler; + } + + + public async Task PublishAsync(string topic, string message) + { + var mqttMsg = new MqttApplicationMessageBuilder() + .WithTopic(topic) + .WithPayload(message) + .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce) + .Build(); + await _mqttClient.PublishAsync(mqttMsg, CancellationToken.None); + } +} \ No newline at end of file diff --git a/OpenAuth.WebApi/Startup.cs b/OpenAuth.WebApi/Startup.cs index 57e7843..dbbbc19 100644 --- a/OpenAuth.WebApi/Startup.cs +++ b/OpenAuth.WebApi/Startup.cs @@ -26,7 +26,6 @@ using SqlSugar; using Swashbuckle.AspNetCore.SwaggerUI; - namespace OpenAuth.WebApi { public class Startup @@ -46,7 +45,10 @@ namespace OpenAuth.WebApi public void ConfigureServices(IServiceCollection services) { services.AddHttpContextAccessor(); + services.AddSingleton(provider => new MqttClientManager()); + #region log4net + //在startup中需要强制创建log4net //var loggerFactory = LoggerFactory.Create(builder => { builder.AddLog4Net(); }); //ILogger logger = loggerFactory.CreateLogger(); @@ -56,9 +58,11 @@ namespace OpenAuth.WebApi loggingBuilder.ClearProviders(); loggingBuilder.AddLog4Net(); }); + #endregion #region identityServer + var identityServer = ((ConfigurationSection)Configuration.GetSection("AppSetting:IdentityServerUrl")).Value; if (!string.IsNullOrEmpty(identityServer)) @@ -73,9 +77,11 @@ namespace OpenAuth.WebApi options.Audience = "openauthapi"; }); } + #endregion #region MiniProfiler + // 添加MiniProfiler服务 //services.AddMiniProfiler(options => //{ @@ -89,13 +95,16 @@ namespace OpenAuth.WebApi // options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter(); // // options.IgnoredPaths.Add("/swagger/"); //}).AddEntityFramework(); //显示SQL语句及耗时 + #endregion #region swagger + //添加swagger services.AddSwaggerGen(option => { #region 注释 + //foreach (var controller in GetControllers()) //{ // var groupname = GetSwaggerGroupName(controller); @@ -114,7 +123,9 @@ namespace OpenAuth.WebApi // option.IncludeXmlComments(name, includeControllerXmlComments: true); //} + #endregion + option.CustomSchemaIds(type => type.FullName); option.SwaggerDoc("v1", new OpenApiInfo { @@ -147,33 +158,35 @@ namespace OpenAuth.WebApi // option.OperationFilter(); // 添加httpHeader参数 //}); + #endregion #region AppSetting + services.Configure(Configuration.GetSection("AppSetting")); + #endregion #region 限制文件大小 - services.Configure(options => - { - options.Limits.MaxRequestBodySize = long.MaxValue; - }); + + services.Configure(options => { options.Limits.MaxRequestBodySize = long.MaxValue; }); services.Configure(x => { x.ValueLengthLimit = int.MaxValue; x.MultipartBodyLengthLimit = long.MaxValue; x.MemoryBufferThreshold = int.MaxValue; - }); + #endregion #region Controllers + services.AddControllers(option => - { - option.Filters.Add(); - //option.Filters.Add(); - //option.Filters.Add(); - }) + { + option.Filters.Add(); + //option.Filters.Add(); + //option.Filters.Add(); + }) .ConfigureApiBehaviorOptions(options => { // 禁用自动模态验证 @@ -194,10 +207,13 @@ namespace OpenAuth.WebApi //options.SerializerSettings.ContractResolver = new DefaultContractResolver(); options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; }); + #endregion #region MemoryCache + services.AddMemoryCache(); + #endregion #region Cors @@ -213,89 +229,98 @@ namespace OpenAuth.WebApi options.AddPolicy("SignalR", builder => builder.SetIsOriginAllowed(origin => true) - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials() - ); + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials() + ); //options.AddPolicy("CorsPolicy", // builder => builder.AllowAnyOrigin() // .AllowAnyMethod() // .AllowAnyHeader()); }); + #endregion #region SqlSugar + ////没有直接 using SqlSugar,因为如果引用命名空间的话,会和Microsoft的一个GetTypeInfo存在二义性,所以就直接这么使用了 services.AddScoped(s => { - StaticConfig.CustomSnowFlakeFunc = () => - { - return Yitter.IdGenerator.YitIdHelper.NextId(); - }; + StaticConfig.CustomSnowFlakeFunc = () => { return Yitter.IdGenerator.YitIdHelper.NextId(); }; var sqlSugar = new SqlSugarClient(new ConnectionConfig() - { - DbType = SqlSugar.DbType.PostgreSQL, - ConnectionString = Configuration.GetConnectionString("OpenAuthDBContext"), - IsAutoCloseConnection = true, - MoreSettings = new SqlSugar.ConnMoreSettings() { - PgSqlIsAutoToLower = false, - PgSqlIsAutoToLowerCodeFirst = false - } - }, - - //var sqlSugar = new SqlSugarClient(new ConnectionConfig() - //{ - // DbType = SqlSugar.DbType.Kdbndp, - // ConnectionString = Configuration.GetConnectionString("OpenAuthDBContext"), - // IsAutoCloseConnection = true, - // MoreSettings = new SqlSugar.ConnMoreSettings() - // { - // //PgSqlIsAutoToLower = false, - // //PgSqlIsAutoToLowerCodeFirst = false, - // IsAutoToUpper = false, - - // DatabaseModel = DbType.PostgreSQL - // } - //}, - db => - { - NpgsqlConnection.GlobalTypeMapper.UseNetTopologySuite(); - //单例参数配置,所有上下文生效 - db.Aop.OnLogExecuting = (sql, pars) => - { - //获取原生SQL推荐 5.1.4.63 性能OK - //UtilMethods.GetNativeSql(sql, pars); - - //获取无参数化SQL 影响性能只适合调试 - //Console.WriteLine(UtilMethods.GetSqlString(DbType.PostgreSQL, sql, pars)); - //Console.WriteLine(sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); - //LogHelper.LogInformation(sql + "\r\n" +db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); - //Console.WriteLine(); - }; - }); + DbType = SqlSugar.DbType.PostgreSQL, + ConnectionString = Configuration.GetConnectionString("OpenAuthDBContext"), + IsAutoCloseConnection = true, + MoreSettings = new SqlSugar.ConnMoreSettings() + { + PgSqlIsAutoToLower = false, + PgSqlIsAutoToLowerCodeFirst = false + } + }, + + //var sqlSugar = new SqlSugarClient(new ConnectionConfig() + //{ + // DbType = SqlSugar.DbType.Kdbndp, + // ConnectionString = Configuration.GetConnectionString("OpenAuthDBContext"), + // IsAutoCloseConnection = true, + // MoreSettings = new SqlSugar.ConnMoreSettings() + // { + // //PgSqlIsAutoToLower = false, + // //PgSqlIsAutoToLowerCodeFirst = false, + // IsAutoToUpper = false, + + // DatabaseModel = DbType.PostgreSQL + // } + //}, + db => + { + NpgsqlConnection.GlobalTypeMapper.UseNetTopologySuite(); + //单例参数配置,所有上下文生效 + db.Aop.OnLogExecuting = (sql, pars) => + { + //获取原生SQL推荐 5.1.4.63 性能OK + //UtilMethods.GetNativeSql(sql, pars); + + //获取无参数化SQL 影响性能只适合调试 + //Console.WriteLine(UtilMethods.GetSqlString(DbType.PostgreSQL, sql, pars)); + //Console.WriteLine(sql + "\r\n" + db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); + //LogHelper.LogInformation(sql + "\r\n" +db.Utilities.SerializeObject(pars.ToDictionary(it => it.ParameterName, it => it.Value))); + //Console.WriteLine(); + }; + }); return sqlSugar; }); - services.AddScoped>(s => new SqlSugar.SugarUnitOfWork(s.GetService())); + services.AddScoped>(s => + new SqlSugar.SugarUnitOfWork(s.GetService())); + #endregion #region HttpClient + services.AddHttpClient(); + #endregion #region DataProtection + services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(Configuration["DataProtection"])); + #endregion #region Quartz + //设置定时启动的任务 - services.AddHostedService(); + //services.AddHostedService(); + #endregion #region SignalR + services.AddSignalR(); + #endregion } @@ -327,27 +352,28 @@ namespace OpenAuth.WebApi //可以在这里为静态文件添加其他http头信息,默认添加跨域信息 ctx.Context.Response.Headers["Access-Control-Allow-Origin"] = "*"; }, - ContentTypeProvider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider(new Dictionary - { - { ".amr","audio/AMR" }, - { ".mp3","audio/mpeg" }, - { ".mp4","video/mp4" }, - { ".apk","application/vnd.android.package-archive" }, - { ".cpg","application/vnd.android.package-archive" }, - { ".dbf","application/vnd.android.package-archive" }, - { ".shp","application/vnd.android.package-archive" }, - { ".shx","application/vnd.android.package-archive" }, - { ".zip","application/zip" }, - { ".jpeg","image/jpeg" }, - { ".jpg","image/jpg" }, - { ".png","image/png" }, - { ".docx","application/msword" }, - { ".doc","application/msword" }, - { ".txt","application/octet-stream" }, - { ".xlsx","application/octet-stream" }, - { ".xls","application/vnd.ms-excel" }, - { ".pdf","application/pdf"} - }) + ContentTypeProvider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider( + new Dictionary + { + { ".amr", "audio/AMR" }, + { ".mp3", "audio/mpeg" }, + { ".mp4", "video/mp4" }, + { ".apk", "application/vnd.android.package-archive" }, + { ".cpg", "application/vnd.android.package-archive" }, + { ".dbf", "application/vnd.android.package-archive" }, + { ".shp", "application/vnd.android.package-archive" }, + { ".shx", "application/vnd.android.package-archive" }, + { ".zip", "application/zip" }, + { ".jpeg", "image/jpeg" }, + { ".jpg", "image/jpg" }, + { ".png", "image/png" }, + { ".docx", "application/msword" }, + { ".doc", "application/msword" }, + { ".txt", "application/octet-stream" }, + { ".xlsx", "application/octet-stream" }, + { ".xls", "application/vnd.ms-excel" }, + { ".pdf", "application/pdf" } + }) }; app.UseStaticFiles(staticfile); //todo:测试可以允许任意跨域,正式环境要加权限 @@ -399,7 +425,7 @@ namespace OpenAuth.WebApi { c.SwaggerEndpoint("v1/swagger.json", "V1 Docs"); c.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None); - c.OAuthClientId("OpenAuth.WebApi"); //oauth客户端名称 + c.OAuthClientId("OpenAuth.WebApi"); //oauth客户端名称 c.OAuthAppName("开源版webapi认证"); // 描述 }); diff --git a/OpenAuth.WebApi/appsettings.json b/OpenAuth.WebApi/appsettings.json index f899b90..d210c9f 100644 --- a/OpenAuth.WebApi/appsettings.json +++ b/OpenAuth.WebApi/appsettings.json @@ -67,5 +67,11 @@ "TiffStoreNamePrefix": "tiff_store", "TiffDir": "E:/tiff" }, - "FlyImageDir": "e:/fly" + "FlyImageDir": "e:/fly", + "MQTT":{ + "Server": "175.27.168.120", + "Port": 6011, + "UserName": "sdhc", + "Password": "" + } }