2021-01-08 17:21:35 +11:00
|
|
|
using System;
|
2019-06-24 11:58:36 +02:00
|
|
|
using System.Threading;
|
2020-07-13 13:38:41 +02:00
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
|
using Microsoft.AspNetCore.Http.Extensions;
|
2020-09-21 09:27:54 +02:00
|
|
|
using Microsoft.Extensions.Logging;
|
2020-03-03 13:42:07 +01:00
|
|
|
using Umbraco.Core.Configuration;
|
2020-03-03 11:18:54 +00:00
|
|
|
using Umbraco.Configuration;
|
2020-07-13 13:38:41 +02:00
|
|
|
using Umbraco.Core;
|
2019-11-20 15:21:09 +01:00
|
|
|
using Umbraco.Core.Hosting;
|
2019-10-29 00:25:03 +11:00
|
|
|
using Umbraco.ModelsBuilder.Embedded.Building;
|
2019-06-24 11:58:36 +02:00
|
|
|
using Umbraco.Web.Cache;
|
2020-08-25 14:19:33 +02:00
|
|
|
using Umbraco.Core.Configuration.Models;
|
|
|
|
|
using Microsoft.Extensions.Options;
|
2021-01-08 17:21:35 +11:00
|
|
|
using Umbraco.Extensions;
|
2019-06-24 11:58:36 +02:00
|
|
|
|
2019-10-29 00:25:03 +11:00
|
|
|
namespace Umbraco.ModelsBuilder.Embedded
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
2019-10-28 21:53:32 +11:00
|
|
|
// supports LiveAppData - but not PureLive
|
2019-06-24 11:58:36 +02:00
|
|
|
public sealed class LiveModelsProvider
|
|
|
|
|
{
|
|
|
|
|
private static Mutex _mutex;
|
|
|
|
|
private static int _req;
|
2020-09-21 09:27:54 +02:00
|
|
|
private readonly ILogger<LiveModelsProvider> _logger;
|
2020-09-18 12:53:10 +02:00
|
|
|
private readonly ModelsBuilderSettings _config;
|
2019-10-28 18:02:52 +11:00
|
|
|
private readonly ModelsGenerator _modelGenerator;
|
2019-10-28 19:08:42 +11:00
|
|
|
private readonly ModelsGenerationError _mbErrors;
|
2019-11-20 15:21:09 +01:00
|
|
|
private readonly IHostingEnvironment _hostingEnvironment;
|
2019-06-24 11:58:36 +02:00
|
|
|
|
|
|
|
|
// we do not manage pure live here
|
2019-10-28 18:02:52 +11:00
|
|
|
internal bool IsEnabled => _config.ModelsMode.IsLiveNotPure();
|
|
|
|
|
|
2020-09-23 07:17:05 +02:00
|
|
|
public LiveModelsProvider(ILogger<LiveModelsProvider> logger, IOptions<ModelsBuilderSettings> config, ModelsGenerator modelGenerator, ModelsGenerationError mbErrors, IHostingEnvironment hostingEnvironment)
|
2019-10-28 18:02:52 +11:00
|
|
|
{
|
|
|
|
|
_logger = logger;
|
2020-08-25 14:19:33 +02:00
|
|
|
_config = config.Value ?? throw new ArgumentNullException(nameof(config));
|
2019-10-28 18:02:52 +11:00
|
|
|
_modelGenerator = modelGenerator;
|
2019-10-28 19:08:42 +11:00
|
|
|
_mbErrors = mbErrors;
|
2019-11-20 15:21:09 +01:00
|
|
|
_hostingEnvironment = hostingEnvironment;
|
2019-10-28 18:02:52 +11:00
|
|
|
}
|
2019-06-24 11:58:36 +02:00
|
|
|
|
2019-10-28 18:02:52 +11:00
|
|
|
internal void Install()
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
|
|
|
|
// just be sure
|
|
|
|
|
if (!IsEnabled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// initialize mutex
|
|
|
|
|
// ApplicationId will look like "/LM/W3SVC/1/Root/AppName"
|
|
|
|
|
// name is system-wide and must be less than 260 chars
|
2019-11-20 15:21:09 +01:00
|
|
|
var name = _hostingEnvironment.ApplicationId + "/UmbracoLiveModelsProvider";
|
2019-10-28 18:02:52 +11:00
|
|
|
|
|
|
|
|
_mutex = new Mutex(false, name); //TODO: Replace this with MainDom? Seems we now have 2x implementations of almost the same thing
|
2019-06-24 11:58:36 +02:00
|
|
|
|
|
|
|
|
// anything changes, and we want to re-generate models.
|
|
|
|
|
ContentTypeCacheRefresher.CacheUpdated += RequestModelsGeneration;
|
|
|
|
|
DataTypeCacheRefresher.CacheUpdated += RequestModelsGeneration;
|
|
|
|
|
|
|
|
|
|
// at the end of a request since we're restarting the pool
|
|
|
|
|
// NOTE - this does NOT trigger - see module below
|
|
|
|
|
//umbracoApplication.EndRequest += GenerateModelsIfRequested;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE
|
|
|
|
|
// Using HttpContext Items fails because CacheUpdated triggers within
|
|
|
|
|
// some asynchronous backend task where we seem to have no HttpContext.
|
|
|
|
|
|
|
|
|
|
// So we use a static (non request-bound) var to register that models
|
|
|
|
|
// need to be generated. Could be by another request. Anyway. We could
|
|
|
|
|
// have collisions but... you know the risk.
|
|
|
|
|
|
2019-10-28 18:02:52 +11:00
|
|
|
private void RequestModelsGeneration(object sender, EventArgs args)
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
|
|
|
|
//HttpContext.Current.Items[this] = true;
|
2020-09-16 10:24:05 +02:00
|
|
|
_logger.LogDebug("Requested to generate models.");
|
2019-06-24 11:58:36 +02:00
|
|
|
Interlocked.Exchange(ref _req, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-13 13:38:41 +02:00
|
|
|
public void GenerateModelsIfRequested()
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
|
|
|
|
//if (HttpContext.Current.Items[this] == null) return;
|
|
|
|
|
if (Interlocked.Exchange(ref _req, 0) == 0) return;
|
|
|
|
|
|
|
|
|
|
// cannot use a simple lock here because we don't want another AppDomain
|
|
|
|
|
// to generate while we do... and there could be 2 AppDomains if the app restarts.
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2020-09-16 10:24:05 +02:00
|
|
|
_logger.LogDebug("Generate models...");
|
2019-10-28 21:53:32 +11:00
|
|
|
const int timeout = 2 * 60 * 1000; // 2 mins
|
2019-06-24 11:58:36 +02:00
|
|
|
_mutex.WaitOne(timeout); // wait until it is safe, and acquire
|
2020-09-15 08:45:40 +02:00
|
|
|
_logger.LogInformation("Generate models now.");
|
2019-06-24 11:58:36 +02:00
|
|
|
GenerateModels();
|
2019-10-28 19:08:42 +11:00
|
|
|
_mbErrors.Clear();
|
2020-09-15 08:45:40 +02:00
|
|
|
_logger.LogInformation("Generated.");
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
catch (TimeoutException)
|
|
|
|
|
{
|
2020-09-16 09:58:07 +02:00
|
|
|
_logger.LogWarning("Timeout, models were NOT generated.");
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2019-10-28 19:08:42 +11:00
|
|
|
_mbErrors.Report("Failed to build Live models.", e);
|
2020-09-16 09:40:49 +02:00
|
|
|
_logger.LogError("Failed to generate models.", e);
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_mutex.ReleaseMutex(); // release
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-28 18:02:52 +11:00
|
|
|
private void GenerateModels()
|
2019-06-24 11:58:36 +02:00
|
|
|
{
|
|
|
|
|
// EnableDllModels will recycle the app domain - but this request will end properly
|
2019-10-28 18:02:52 +11:00
|
|
|
_modelGenerator.GenerateModels();
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-13 13:38:41 +02:00
|
|
|
public void AppEndRequest(HttpContext context)
|
|
|
|
|
{
|
2021-01-08 17:21:35 +11:00
|
|
|
if (context.Request.IsClientSideRequest())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-13 13:38:41 +02:00
|
|
|
|
2021-01-08 17:21:35 +11:00
|
|
|
if (!IsEnabled)
|
|
|
|
|
{
|
2020-07-13 13:38:41 +02:00
|
|
|
return;
|
2021-01-08 17:21:35 +11:00
|
|
|
}
|
2019-10-28 21:53:32 +11:00
|
|
|
|
2020-07-13 13:38:41 +02:00
|
|
|
GenerateModelsIfRequested();
|
|
|
|
|
}
|
2019-06-24 11:58:36 +02:00
|
|
|
}
|
|
|
|
|
}
|