diff --git a/projects/IoTCenter/Api/ProductController.cs b/projects/IoTCenter/Api/ProductController.cs index 9ed2c797..e32335ec 100644 --- a/projects/IoTCenter/Api/ProductController.cs +++ b/projects/IoTCenter/Api/ProductController.cs @@ -35,21 +35,25 @@ namespace IoTCenter.Api.Controllers { try { - var model = this._productRepo.ReadOnlyTable() - .OrderBy(o => o.DisplayOrder) - .ThenBy(o => o.Name) - .ToList() - .Select(o => new - { - o.Id, - o.Name, - o.Number, - o.Image, - o.DisplayOrder, - Count = _deviceRepo.ReadOnlyTable() - .WhereIf(!string.IsNullOrWhiteSpace(organNumber), o => o.Node.OrganNodes.Any(o => o.Organ.Number == organNumber)) - .Count(d => d.ProductId == o.Id) - }); + var model = this._organNodeRepo.ReadOnlyTable() + .WhereIf(!string.IsNullOrEmpty(organNumber), o => o.Organ.Number == organNumber) + .SelectMany(o => o.Node.Devices) + .GroupBy(o => new + { + o.Product.Id, + o.Product.Name, + o.Product.Number, + o.Product.DisplayOrder + }) + .Select(o => new + { + o.Key.Id, + o.Key.Name, + o.Key.Number, + o.Key.DisplayOrder, + Count = o.Count() + }) + .ToList(); return Ok(model); } catch (Exception ex) @@ -65,12 +69,13 @@ namespace IoTCenter.Api.Controllers try { var model = this._productRepo.ReadOnlyTable().Where(o => o.Number == number).FirstOrDefault(); - model.Devices = this._deviceRepo.ReadOnlyTable() - .Where(o => o.Product.Id == model.Id) - .WhereIf(!string.IsNullOrWhiteSpace(organNumber), o => o.Node.OrganNodes.Any(o => o.Organ.Number == organNumber)) - .Include(o => o.Node) - .Include(o => o.Data) - .ToList(); + model.Devices = this._organNodeRepo.ReadOnlyTable() + .WhereIf(!string.IsNullOrEmpty(organNumber), o => o.Organ.Number == organNumber) + .SelectMany(o => o.Node.Devices) + .Include(o => o.Data) + .ToList() + .Where(o => o.ProductId == model.Id) + .ToList(); return Ok(model); } catch (Exception ex) diff --git a/projects/IoTCenter/Api/SiteController.cs b/projects/IoTCenter/Api/SiteController.cs index d6eb9e23..44892abd 100644 --- a/projects/IoTCenter/Api/SiteController.cs +++ b/projects/IoTCenter/Api/SiteController.cs @@ -1,4 +1,6 @@ using Application.Domain.Entities; +using Hangfire; +using Hangfire.Storage; using Infrastructure.Application.Services.Settings; using Infrastructure.Data; using Infrastructure.Extensions; @@ -87,7 +89,12 @@ namespace IoTCenter.Api.Controllers [HttpPost] public IActionResult UpdateTimer() { - this.RemoveJobs(); + using var conn = JobStorage.Current.GetConnection(); + var jobs = conn.GetRecurringJobs(); + foreach (var job in jobs) + { + RecurringJob.RemoveIfExists(job.Id); + } var timers = this._organSceneTimerRepo.ReadOnlyTable().ToList(); foreach (var timer in timers) { diff --git a/projects/IoTCenter/IoTCenter.csproj b/projects/IoTCenter/IoTCenter.csproj index e96f01e6..28cda419 100644 --- a/projects/IoTCenter/IoTCenter.csproj +++ b/projects/IoTCenter/IoTCenter.csproj @@ -9,6 +9,9 @@ Linux + + + diff --git a/projects/IoTCenter/Startup.cs b/projects/IoTCenter/Startup.cs index 5285e65d..0f3ddddd 100644 --- a/projects/IoTCenter/Startup.cs +++ b/projects/IoTCenter/Startup.cs @@ -1,15 +1,22 @@ -using Infrastructure.Data; +using Hangfire; +using Hangfire.Dashboard.BasicAuthorization; +using Hangfire.MySql; +using Infrastructure.Data; using Infrastructure.Email; using Infrastructure.Sms; using Infrastructure.UI; using Infrastructure.Web; using IoT.Shared.Services; using IoTCenter.Services; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; using System.Collections.Generic; +using System.Transactions; namespace IoTCenter { @@ -30,6 +37,47 @@ namespace IoTCenter services.AddTransient(); services.AddHostedService(); base.ConfigureServices(services); + var connectionString = Configuration.GetConnectionString("HangfireConnection"); + services.AddHangfire(configuration => configuration.UseStorage(new MySqlStorage(connectionString, new MySqlStorageOptions + { + TransactionIsolationLevel = IsolationLevel.ReadCommitted, + QueuePollInterval = TimeSpan.FromSeconds(15), + JobExpirationCheckInterval = TimeSpan.FromHours(1), + CountersAggregateInterval = TimeSpan.FromMinutes(5), + PrepareSchemaIfNecessary = true, + DashboardJobListLimit = 50000, + TransactionTimeout = TimeSpan.FromMinutes(1), + TablesPrefix = "Hangfire" + }))); + } + + public override void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) + { + base.Configure(app, env, loggerFactory); + var options = new DashboardOptions + { + Authorization = new[] { new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions + { + RequireSsl = false, + SslRedirect = false, + LoginCaseSensitive = true, + Users = new [] + { + new BasicAuthAuthorizationUser + { + Login = Configuration["auth:usr"], + PasswordClear = Configuration["auth:pwd"] + } + } + }) } + }; + + app.UseHangfireDashboard("/job", options); + + app.UseHangfireServer(new BackgroundJobServerOptions + { + ServerName = $"IoTCenter:{Guid.NewGuid()}", + }); } public override void ConfigureOptions(IServiceCollection services) diff --git a/projects/IoTCenter/appsettings.Development.json b/projects/IoTCenter/appsettings.Development.json index 45fe774a..89be7064 100644 --- a/projects/IoTCenter/appsettings.Development.json +++ b/projects/IoTCenter/appsettings.Development.json @@ -1,9 +1,19 @@ -{ +{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } + }, + "ConnectionStrings": { + "postgresql": "User ID=root;Host=localhost;Port=26257;Database=iotcenter;CommandTimeout=600;TrustServerCertificate=true;", + "sqlite": "Data Source=iotcenter.db", + "mysql": "Server=localhost;Port=3306;Database=iotcenter;Uid=root;Pwd=aA123456!;", + "HangfireConnection": "Server=localhost;Port=3306;Database=jobserver;Uid=root;Pwd=aA123456!;Allow User Variables=True;", + "redis": "localhost:6379,password=aA123456!,allowAdmin=true", + "srs": "http://localhost:1985", + "JobServer": "http://localhost/JobServer", + "JobCallBack": "http://localhost/IoTCenter/api/v1/Api/ExecTimer" } } \ No newline at end of file diff --git a/projects/IoTCenter/appsettings.Docker.json b/projects/IoTCenter/appsettings.Docker.json index 5ac01f23..5c32a172 100644 --- a/projects/IoTCenter/appsettings.Docker.json +++ b/projects/IoTCenter/appsettings.Docker.json @@ -5,6 +5,7 @@ "ConnectionStrings": { "postgresql": "User ID=root;Host=postgresql;Port=26257;Database=iotcenter;CommandTimeout=120", "mysql": "Server=172.172.0.30;Port=3306;Database=iotcenter;Uid=root;Pwd=aA123456!;", + "HangfireConnection": "Server=172.172.0.30;Port=3306;Database=jobserver;Uid=root;Pwd=aA123456!;Allow User Variables=True;", "redis": "172.172.0.40:6379,password=aA123456!,allowAdmin=true", "srs": "http://172.172.0.60:1985", "JobServer": "http://172.172.0.12/JobServer", diff --git a/projects/IoTCenter/appsettings.json b/projects/IoTCenter/appsettings.json index f4b0ca92..a39048a0 100644 --- a/projects/IoTCenter/appsettings.json +++ b/projects/IoTCenter/appsettings.json @@ -59,6 +59,7 @@ "postgresql": "User ID=root;Host=localhost;Port=26257;Database=iotcenter;CommandTimeout=600;TrustServerCertificate=true;", "sqlite": "Data Source=iotcenter.db", "mysql": "Server=mysql;Port=3306;Database=iotcenter;Uid=root;Pwd=aA123456!;", + "HangfireConnection": "Server=mysql;Port=3306;Database=jobserver;Uid=root;Pwd=aA123456!;Allow User Variables=True;", "redis": "redis:6379,password=aA123456!,allowAdmin=true", "srs": "http://srs:1985", "JobServer": "http://jobserver/JobServer", @@ -81,5 +82,9 @@ "username": "admin", "password": "admin" } + }, + "auth": { + "usr": "admin", + "pwd": "admin" } } \ No newline at end of file diff --git a/projects/UserCenter/appsettings.Development.json b/projects/UserCenter/appsettings.Development.json index 45fe774a..51598c5f 100644 --- a/projects/UserCenter/appsettings.Development.json +++ b/projects/UserCenter/appsettings.Development.json @@ -1,9 +1,15 @@ -{ +{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } + }, + "ConnectionStrings": { + "postgresql": "User ID=root;Host=localhost;Port=26257;Database=usercenter;CommandTimeout=120", + "sqlite": "Data Source=usercenter.db", + "mysql": "Server=localhost;Port=3306;Database=usercenter;Uid=root;Pwd=aA123456!;", + "redis": "localhost:6379,password=aA123456!,allowAdmin=true" } } \ No newline at end of file diff --git a/projects/projects.sln b/projects/projects.sln index 41c34d27..202a2385 100644 --- a/projects/projects.sln +++ b/projects/projects.sln @@ -39,8 +39,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{11BCB5F9-0020- EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "WebSPA\WebSPA.csproj", "{6F839910-580D-4CD1-A0C0-6FAF542B4480}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JobServer", "JobServer\JobServer.csproj", "{6E2766D8-9ECF-469E-8662-A20F673E52CC}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IoTDameon", "IoTDameon\IoTDameon.csproj", "{60596088-3C4E-4EA2-933A-B66CD269845B}" EndProject Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{5AEB0613-6424-4A0A-A36E-2CBBA8BD264C}" @@ -151,18 +149,6 @@ Global {6F839910-580D-4CD1-A0C0-6FAF542B4480}.Release|iPhone.Build.0 = Release|Any CPU {6F839910-580D-4CD1-A0C0-6FAF542B4480}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {6F839910-580D-4CD1-A0C0-6FAF542B4480}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Debug|iPhone.Build.0 = Debug|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Release|Any CPU.Build.0 = Release|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Release|iPhone.ActiveCfg = Release|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Release|iPhone.Build.0 = Release|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {6E2766D8-9ECF-469E-8662-A20F673E52CC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {60596088-3C4E-4EA2-933A-B66CD269845B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {60596088-3C4E-4EA2-933A-B66CD269845B}.Debug|Any CPU.Build.0 = Debug|Any CPU {60596088-3C4E-4EA2-933A-B66CD269845B}.Debug|iPhone.ActiveCfg = Debug|Any CPU @@ -200,11 +186,10 @@ Global {BE6DEBC5-004F-4811-8BDC-67C74D9E8C2F} = {AE34E06D-C5C7-44BC-B168-85808318516C} {C66B39B3-D863-4651-99CD-74104CA65C47} = {11BCB5F9-0020-463A-92FB-BC25E2A0BF75} {6F839910-580D-4CD1-A0C0-6FAF542B4480} = {11BCB5F9-0020-463A-92FB-BC25E2A0BF75} - {6E2766D8-9ECF-469E-8662-A20F673E52CC} = {E1681DC3-9AC2-4FF6-B3DE-37EF826E6F8A} {60596088-3C4E-4EA2-933A-B66CD269845B} = {AE34E06D-C5C7-44BC-B168-85808318516C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - BuildVersion_StartDate = 2000/1/1 SolutionGuid = {0B7095FB-5E70-4EF8-805A-CB4A91AE4B0A} + BuildVersion_StartDate = 2000/1/1 EndGlobalSection EndGlobal