This example illustrates various parameters that can be adjusted when using the on-premise device detection engine, and controls when a new data file is sought and when it is loaded by the device detection software.Three main aspects are demonstrated:
In order to test this example you will need a 51Degrees Enterprise license which can be purchased from our pricing page.
Enterprise (fully-featured) data files are typically released by 51Degrees five days a week (Mon-Fri) and on-premise deployments can fetch and download those files automatically. Equally, customers may choose to download the files themselves and move them into place to be detected by the 51Degrees filesystem watcher.
Lite data files (free-to-use, limited capabilities, no license key required) are created roughly once a month and cannot be updated using auto-update, they may be downloaded from Github and are included with source distributions of this software.
You can configure the pipeline builder to download an Enterprise data file on start-up.
You can configure the pipeline builder to watch for changes to the currently loaded device detection data file, and to replace the file currently in use with the new one. This is useful, for example, if you wish to download and update the device detection file "manually" - i.e. you would download it then drop it into place with the same path as the currently loaded file.
Enterprise data files are usually created four times a week. Each data file contains a date for when the next data file is expected. You can configure the pipeline so that it starts looking for a newer data file after that time, by connecting to the 51Degrees distributor to see if an update is available. If one is, then it is downloaded and will replace the existing device detection file, which is currently in use.
using FiftyOne.Pipeline.Engines.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.IO;
using System.Net.Http;
{
public class Program
{
public class Example : ExampleBase
{
public DeviceDetectionPipelineBuilder
PipelineBuilder {
get;
private set; }
public DeviceDetectionHashEngineBuilder
EngineBuilder {
get;
private set; }
public ILogger<Example> Logger { get; private set; }
private TimeSpan _updateTimeout = new TimeSpan(0, 0, 20);
private CompletionListener CompletionListener;
public Example(DeviceDetectionPipelineBuilder pipelineBuilder,
DeviceDetectionHashEngineBuilder engineBuilder,
CompletionListener completionListener,
ILogger<Example> logger)
{
CompletionListener = completionListener;
Logger = logger;
}
public void Run(
string dataFile,
string licenseKey,
bool interactive)
{
Logger.LogInformation("Starting example");
licenseKey = CheckLicenseKey(licenseKey, Logger);
dataFile = CheckDataFile(dataFile, Logger);
string copyDataFile = dataFile + ".bak";
if (File.Exists(dataFile))
{
var metadata = ExampleUtils.GetDataFileInfo(dataFile,
EngineBuilder);
ExampleUtils.LogDataFileInfo(metadata, Logger);
if (metadata.Tier.Equals("Lite"))
{
Logger.LogError("Will not download an 'Enterprise' data file over the top of " +
"a 'Lite' data file, please supply another location.");
throw new ArgumentException("File supplied has wrong data tier");
}
Logger.LogInformation("Existing data file will be replaced with downloaded data file");
Logger.LogInformation("Existing data file will be copied to {}", copyDataFile);
}
if (interactive)
{
Logger.LogWarning("Please note - this example will use available downloads " +
"in your licensed allocation.");
Logger.LogWarning("Do you wish to continue with this example (y)? ");
var key = Console.ReadKey();
if (key.Key != ConsoleKey.Y)
{
Logger.LogInformation("Stopping example without download");
return;
}
}
if (File.Exists(dataFile))
{
File.Copy(dataFile, copyDataFile, true);
Logger.LogInformation("Existing data file copied to {}", copyDataFile);
}
Logger.LogInformation("Creating pipeline and initiating update on start-up - " +
"please wait for that to complete");
try
{
.UseOnPremise(dataFile, licenseKey, true)
.SetDataUpdateOnStartUp(true)
.SetAutoUpdate(true)
.SetDataFileSystemWatcher(true)
.SetUpdatePollingInterval(1)
.Build())
{
Logger.LogInformation("Update on start-up complete - status - " +
CompletionListener.Result.Status);
if (CompletionListener.Result.Status == AutoUpdateStatus.AUTO_UPDATE_SUCCESS ||
CompletionListener.Result.Status == AutoUpdateStatus.AUTO_UPDATE_NOT_NEEDED)
{
Logger.LogInformation("Modifying downloaded file to trigger reload ... " +
"please wait for that to complete");
CompletionListener.Reset();
try
{
new FileInfo(dataFile).LastWriteTimeUtc = DateTime.UtcNow;
}
catch (IOException)
{
throw new InvalidOperationException("Could not modify file time, " +
"abandoning example");
}
try
{
CompletionListener.WaitForComplete(_updateTimeout);
Logger.LogInformation($"Update on file modification complete, " +
$"status: {CompletionListener.Result.Status}");
}
catch (TimeoutException)
{
Logger.LogError("Timeout waiting for engine to refresh data.");
}
}
else
{
Logger.LogError("Auto update was not successful, abandoning example");
throw new InvalidOperationException("Auto update failed: " +
CompletionListener.Result.Status);
}
Logger.LogInformation("Finished Example");
}
}
catch (Pipeline.Engines.Exceptions.DataUpdateException ex)
{
if (ex.Status != AutoUpdateStatus.AUTO_UPDATE_ERR_429_TOO_MANY_ATTEMPTS)
{
throw;
}
Logger.LogWarning("Auto update failed with 429 status code, " +
"abandoning example");
}
}
private string CheckLicenseKey(string licenseKey, ILogger logger)
{
if (licenseKey == null)
{
licenseKey = Environment.GetEnvironmentVariable(Constants.LICENSE_KEY_ENV_VAR);
}
const string keySubmissionPaths = "as the second command line argument to this program, or as " +
$"an environment variable named '{Constants.LICENSE_KEY_ENV_VAR}'";
if (licenseKey == null)
{
logger.LogError("In order to test this example you will need a 51Degrees " +
"Enterprise license which can be obtained on a trial basis or purchased " +
"from our pricing page https://51degrees.com/pricing. You must supply the " +
"license key " + keySubmissionPaths);
throw new ArgumentException("No license key available", nameof(licenseKey));
}
if (ExampleUtils.IsInvalidKey(licenseKey))
{
logger.LogWarning("The license key supplied (" + keySubmissionPaths + ") is probably invalid.");
}
return licenseKey;
}
private string CheckDataFile(string dataFile, ILogger logger)
{
if (dataFile == null)
{
dataFile = Constants.ENTERPRISE_HASH_DATA_FILE_NAME;
logger.LogWarning($"No filename specified. Using default '{dataFile}'");
}
if (dataFile != null && Path.IsPathRooted(dataFile) == false)
{
var fullPath = ExampleUtils.FindFile(dataFile);
if (fullPath == null)
{
dataFile = Path.Combine(Directory.GetCurrentDirectory(), dataFile);
logger.LogWarning($"File '{dataFile}' not found, a file will be " +
$"downloaded to that location on start-up");
}
else
{
dataFile = fullPath;
}
}
else if (dataFile != null && File.Exists(dataFile) == false)
{
if (new FileInfo(dataFile).Directory.Exists == false)
{
logger.LogError("The directory must exist when specifying a " +
"location for a new file to be downloaded. Path specified was " +
$"'{dataFile}'");
throw new ArgumentException("Directory for new file must exist",
nameof(dataFile));
}
else
{
logger.LogWarning($"File '{dataFile}' not found, a file will be " +
$"downloaded to that location on start-up");
}
}
return dataFile;
}
}
public static void Main(string[] args)
{
var dataFile = args.Length > 0 ? args[0] : null;
var licenseKey = args.Length > 1 ? args[1] : null;
Initialize(dataFile, licenseKey, true);
}
public static void Initialize(
string dataFile, string licenseKey, bool interactive)
{
using (var serviceProvider = new ServiceCollection()
.AddLogging(l => l
.AddConsole()
.AddFilter((c, l) =>
{
return l >= LogLevel.Warning ||
(c.StartsWith(typeof(Program).FullName) && l >= LogLevel.Information);
}))
.AddSingleton<HttpClient>()
.AddSingleton<IDataUpdateService, DataUpdateService>()
.AddTransient<DeviceDetectionPipelineBuilder>()
.AddTransient<DeviceDetectionHashEngineBuilder>()
.AddSingleton<Example>()
.AddSingleton<CompletionListener>()
.BuildServiceProvider())
{
var example = serviceProvider.GetRequiredService<Example>();
example.Run(dataFile, licenseKey, interactive);
}
}
}
}