Skip to content

Commit

Permalink
Merged Pull Request '#76 lazify-ClientsidePropertyService-headers->ma…
Browse files Browse the repository at this point in the history
…in : Lazify clientside property service headers'

Lazify clientside property service headers
  • Loading branch information
Automation51D authored Dec 2, 2023
2 parents b09c1a7 + fb21348 commit d0963c9
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 70 deletions.
1 change: 1 addition & 0 deletions .github/workflows/monthly-copyright-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/monthly-copyright-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/nightly-documentation-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-documentation-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/nightly-package-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-package-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/nightly-prs-to-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-prs-to-main.yml@main
with:
repo-name: ${{ github.event.repository.name }}
org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/nightly-publish-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-publish-main.yml@main
with:
repo-name: ${{ github.event.repository.name }}
org-name: ${{ github.event.repository.owner.login }}
build-platform: windows-latest
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/nightly-submodule-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-submodule-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,49 @@ protected override void ManagedResourcesCleanup()
/// </exception>
protected override void ProcessInternal(IFlowData data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
SetUp(data);
SetUp(data, GetJSONFromData(data), GetOrAddToData(data), true);
}


/// <summary>
/// Default process method.
/// </summary>
/// <param name="data"></param>
/// <param name="jsonData"></param>
/// <exception cref="ArgumentNullException">
/// Thrown if the supplied flow data is null.
/// </exception>
public JavaScriptBuilderElementData GetFallbackResponse(IFlowData data, IJsonBuilderElementData jsonData)
{
if (jsonData == null)
{
throw new ArgumentNullException(nameof(jsonData));
}
JavaScriptBuilderElementData result = (JavaScriptBuilderElementData)CreateElementData(data.Pipeline);
SetUp(data, () => jsonData, () => result, false);
return result;
}

private void SetUp(IFlowData data)
private static Func<IJsonBuilderElementData> GetJSONFromData(IFlowData data) => () =>
{
try
{
return data.Get<IJsonBuilderElementData>();
}
catch (KeyNotFoundException ex)
{
throw new PipelineConfigurationException(
Messages.ExceptionJsonBuilderNotRun, ex);
}
};

private void SetUp(
IFlowData data,
Func<IJsonBuilderElementData> jsonDataProvider,
Func<JavaScriptBuilderElementData> targetElementDataProvider,
bool throwOnGetAsFailure)
{
if (data == null) throw new ArgumentNullException(nameof(data));
var host = Host;
var protocol = Protocol;
bool supportsPromises = false;
Expand All @@ -276,6 +313,8 @@ private void SetUp(IFlowData data)
protocol = Constants.FALLBACK_PROTOCOL;
}

const string errorFormat_GetAsFailed = "Failed to get property {propertyName}";

// If device detection is in the Pipeline then we can check
// if the client's browser supports promises.
// This can be used to customize the JavaScript response.
Expand All @@ -292,7 +331,19 @@ private void SetUp(IFlowData data)

try
{
var promise = data.GetAs<IAspectPropertyValue<string>>("Promise");
IAspectPropertyValue<string> promise = null;
try
{
promise = data.GetAs<IAspectPropertyValue<string>>("Promise");
}
catch (Exception ex)
{
if (throwOnGetAsFailure)
{
throw;
}
Logger.LogError(ex, errorFormat_GetAsFailed, "Promise");
}
supportsPromises = promise != null && promise.HasValue && promise.Value == "Full";
}
catch (PropertyMissingException) { promisesNotAvailable(); }
Expand All @@ -317,7 +368,19 @@ private void SetUp(IFlowData data)

try
{
var fetch = data.GetAs<IAspectPropertyValue<bool>>("Fetch");
IAspectPropertyValue<bool> fetch = null;
try
{
fetch = data.GetAs<IAspectPropertyValue<bool>>("Fetch");
}
catch (Exception ex)
{
if (throwOnGetAsFailure)
{
throw;
}
Logger.LogError(ex, errorFormat_GetAsFailed, "Fetch");
}
supportsFetch = fetch != null && fetch.HasValue && fetch.Value;
}
catch (PropertyMissingException) { fetchNotAvailable(); }
Expand All @@ -327,16 +390,8 @@ private void SetUp(IFlowData data)
}

// Get the JSON include to embed into the JavaScript include.
string jsonObject = string.Empty;
try
{
jsonObject = data.Get<IJsonBuilderElementData>().Json;
}
catch (KeyNotFoundException ex)
{
throw new PipelineConfigurationException(
Messages.ExceptionJsonBuilderNotRun, ex);
}
string jsonObject = jsonDataProvider().Json;


var parameters = GetParameters(data);
var paramsObject = JsonConvert.SerializeObject(parameters);
Expand Down Expand Up @@ -380,7 +435,7 @@ private void SetUp(IFlowData data)
}

// With the gathered resources, build a new JavaScriptResource.
BuildJavaScript(data, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, url, paramsObject);
BuildJavaScript(data, targetElementDataProvider, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, url, paramsObject);
}


Expand Down Expand Up @@ -474,6 +529,12 @@ protected virtual string GetSessionId(IFlowData data)
/// <param name="data">
/// The <see cref="IFlowData"/> instance to populate with the
/// resulting <see cref="JavaScriptBuilderElementData"/>
/// and additional evidence source
/// </param>
/// <param name="targetElementDataProvider">
/// The method the will inject the resulting
/// <see cref="JavaScriptBuilderElementData"/>
/// into the response (even if differs from `data` above)
/// </param>
/// <param name="jsonObject">
/// The JSON data object to include in the JavaScript.
Expand Down Expand Up @@ -503,6 +564,7 @@ protected virtual string GetSessionId(IFlowData data)
/// </exception>
protected void BuildJavaScript(
IFlowData data,
Func<JavaScriptBuilderElementData> targetElementDataProvider,
string jsonObject,
string sessionId,
int sequence,
Expand All @@ -511,7 +573,15 @@ protected void BuildJavaScript(
string url,
string parameters)
{
BuildJavaScript(data, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, new Uri(url), parameters);
BuildJavaScript(data, targetElementDataProvider, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, new Uri(url), parameters);
}

private Func<JavaScriptBuilderElementData> GetOrAddToData(IFlowData data)
{
return () => (JavaScriptBuilderElementData)
data.GetOrAdd(
ElementDataKeyTyped,
CreateElementData);
}

/// <summary>
Expand All @@ -521,6 +591,12 @@ protected void BuildJavaScript(
/// <param name="data">
/// The <see cref="IFlowData"/> instance to populate with the
/// resulting <see cref="JavaScriptBuilderElementData"/>
/// and additional evidence source
/// </param>
/// <param name="targetElementDataProvider">
/// The method the will inject the resulting
/// <see cref="JavaScriptBuilderElementData"/>
/// into the response (even if differs from `data` above)
/// </param>
/// <param name="jsonObject">
/// The JSON data object to include in the JavaScript.
Expand Down Expand Up @@ -549,7 +625,8 @@ protected void BuildJavaScript(
/// Thrown if the supplied flow data is null.
/// </exception>
protected void BuildJavaScript(
IFlowData data,
IFlowData data,
Func<JavaScriptBuilderElementData> targetElementDataProvider,
string jsonObject,
string sessionId,
int sequence,
Expand All @@ -558,12 +635,9 @@ protected void BuildJavaScript(
Uri url,
string parameters)
{
if (data == null) throw new ArgumentNullException(nameof(data));

JavaScriptBuilderElementData elementData = (JavaScriptBuilderElementData)
data.GetOrAdd(
ElementDataKeyTyped,
CreateElementData);
if (data == null) throw new ArgumentNullException(nameof(data));

JavaScriptBuilderElementData elementData = targetElementDataProvider();

string objectName = ObjName;
// Try and get the requested object name from evidence.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,34 @@ public void JavaScriptBuilder_VerifySession()
$"JavaScript does not contain expected sequence '1'.");
}

/// <summary>
/// Check that the callback URL is generated correctly.
/// </summary>
[TestMethod]
public void JavaScriptBuilder_VerifyFallbackResponse()
{
_javaScriptBuilderElement =
new JavaScriptBuilderElementBuilder(_loggerFactory)
.SetEndpoint("/json")
.Build();

var flowData = new Mock<IFlowData>();

flowData.Setup(d => d.Get<IJsonBuilderElementData>())
.Throws<KeyNotFoundException>();
var evidence = new Evidence(_loggerFactory.CreateLogger<Evidence>());
flowData.Setup(d => d.GetEvidence())
.Returns(evidence);

var jsonData = new Mock<IJsonBuilderElementData>();
jsonData.Setup(j => j.Json)
.Returns("{}");

IJavaScriptBuilderElementData result = _javaScriptBuilderElement.GetFallbackResponse(flowData.Object, jsonData.Object);

Assert.IsFalse(string.IsNullOrWhiteSpace(result.JavaScript));
}

/// <summary>
/// Check that the callback URL is generated correctly.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,31 @@ protected override void ManagedResourcesCleanup()
/// <exception cref="ArgumentNullException">
/// Thrown if the supplied flow data is null.
/// </exception>
protected override void ProcessInternal(IFlowData data)
protected override void ProcessInternal(IFlowData data) =>
BuildAndInjectJSON(
data,
data.GetOrAdd(
ElementDataKeyTyped,
CreateElementData),
true);

/// <summary>
/// Transform the data in the flow data instance into a
/// JSON object.
/// </summary>
/// <param name="data">
/// The <see cref="IFlowData"/>
/// </param>
/// <param name="elementData">
/// The <see cref="IJsonBuilderElementData"/>
/// </param>
/// <param name="requireSequenceNumber">
/// Whether to throw if sequence number was not found
/// </param>
/// <exception cref="ArgumentNullException">
/// Thrown if the supplied flow data is null.
/// </exception>
private void BuildAndInjectJSON(IFlowData data, IJsonBuilderElementData elementData, bool requireSequenceNumber)
{
if (data == null) throw new ArgumentNullException(nameof(data));

Expand All @@ -225,32 +249,59 @@ protected override void ProcessInternal(IFlowData data)
config = _pipelineConfigs.GetOrAdd(data.Pipeline, config);
}

var elementData = data.GetOrAdd(
ElementDataKeyTyped,
CreateElementData);
var jsonString = BuildJson(data, config);
var jsonString = BuildJson(data, config, requireSequenceNumber);
elementData.Json = jsonString;
}

/// <summary>
/// Transform the data in the flow data instance into a
/// JSON object.
/// </summary>
/// <param name="data">
/// The <see cref="IFlowData"/>
/// </param>
/// <exception cref="ArgumentNullException">
/// Thrown if the supplied flow data is null.
/// </exception>
public IJsonBuilderElementData GetFallbackResponse(IFlowData data)
{
var elementData = CreateElementData(data.Pipeline);
BuildAndInjectJSON(data, elementData, false);
return elementData;
}

/// <summary>
/// Create and populate a JSON string from the specified data.
/// </summary>
/// <param name="data"></param>
/// <param name="config">The configuration to use</param>
/// <param name="requireSequenceNumber">The configuration to use</param>
/// <returns>
/// A string containing the data in JSON format.
/// </returns>
protected virtual string BuildJson(IFlowData data, PipelineConfig config)
protected virtual string BuildJson(IFlowData data, PipelineConfig config, bool requireSequenceNumber)
{
int sequenceNumber = GetSequenceNumber(data);
int? sequenceNumber = null;
try
{
sequenceNumber = GetSequenceNumber(data);
}
catch (PipelineException e)
{
if (requireSequenceNumber)
{
throw;
}
Logger.LogError(e, $"Failed to get {nameof(sequenceNumber)}.");
}

// Get property values from all the elements and add the ones that
// are accessible to a dictionary.
Dictionary<String, object> allProperties = GetAllProperties(data, config);

// Only populate the JavaScript properties if the sequence
// has not reached max iterations.
if (sequenceNumber < Constants.MAX_JAVASCRIPT_ITERATIONS)
if (!sequenceNumber.HasValue || sequenceNumber.Value < Constants.MAX_JAVASCRIPT_ITERATIONS)
{
AddJavaScriptProperties(data, allProperties);
}
Expand Down
Loading

0 comments on commit d0963c9

Please sign in to comment.