diff --git a/modules/evaluation-server/src/Api/Public/SdkController.cs b/modules/evaluation-server/src/Api/Public/SdkController.cs new file mode 100644 index 000000000..753e1d4ad --- /dev/null +++ b/modules/evaluation-server/src/Api/Public/SdkController.cs @@ -0,0 +1,59 @@ +using Domain.EndUsers; +using Domain.Services; +using Microsoft.AspNetCore.Mvc; + +namespace Api.Public; + +public class SdkController : PublicApiControllerBase +{ + private readonly IDataSyncService _dataSyncService; + + public SdkController(IDataSyncService dataSyncService) + { + _dataSyncService = dataSyncService; + } + + [HttpGet("server/latest-all")] + public async Task GetServerSideSdkPayloadAsync() + { + if (!Authenticated) + { + return Unauthorized(); + } + + var payload = await _dataSyncService.GetServerSdkPayloadAsync(EnvId, 0); + + var bootstrap = new + { + messageType = "data-sync", + data = payload + }; + + return new JsonResult(bootstrap); + } + + [HttpPost("client/latest-all")] + public async Task GetClientSdkPayloadAsync(EndUser endUser) + { + if (!Authenticated) + { + return Unauthorized(); + } + + if (!endUser.IsValid()) + { + return BadRequest("invalid end user"); + } + + var payload = await _dataSyncService.GetClientSdkPayloadAsync(EnvId, endUser, 0); + + var bootstrap = payload.FeatureFlags.Select(x => new + { + x.Id, + x.Variation, + x.VariationType + }); + + return new JsonResult(bootstrap); + } +} \ No newline at end of file diff --git a/modules/evaluation-server/src/Domain/Services/IDataSyncService.cs b/modules/evaluation-server/src/Domain/Services/IDataSyncService.cs index cc67d54cf..ad0201549 100644 --- a/modules/evaluation-server/src/Domain/Services/IDataSyncService.cs +++ b/modules/evaluation-server/src/Domain/Services/IDataSyncService.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using Domain.EndUsers; using Domain.Protocol; using Domain.WebSockets; @@ -8,6 +9,10 @@ public interface IDataSyncService { Task GetPayloadAsync(Connection connection, DataSyncMessage message); + Task GetClientSdkPayloadAsync(Guid envId, EndUser user, long timestamp); + + Task GetServerSdkPayloadAsync(Guid envId, long timestamp); + Task GetFlagChangePayloadAsync(Connection connection, JsonElement flag); Task GetSegmentChangePayloadAsync(Connection connection, JsonElement segment, string[] affectedFlagIds); diff --git a/modules/evaluation-server/src/Infrastructure/Services/DataSyncService.cs b/modules/evaluation-server/src/Infrastructure/Services/DataSyncService.cs index 3160ae3d0..e2824ac78 100644 --- a/modules/evaluation-server/src/Infrastructure/Services/DataSyncService.cs +++ b/modules/evaluation-server/src/Infrastructure/Services/DataSyncService.cs @@ -41,6 +41,47 @@ public async Task GetPayloadAsync(Connection connection, DataSyncMessage return payload; } + public async Task GetClientSdkPayloadAsync(Guid envId, EndUser user, long timestamp) + { + var eventType = timestamp == 0 ? DataSyncEventTypes.Full : DataSyncEventTypes.Patch; + var flagsBytes = await _cacheService.GetFlagsAsync(envId, timestamp); + + var clientSdkFlags = new List(); + foreach (var flagBytes in flagsBytes) + { + using var document = JsonDocument.Parse(flagBytes); + var flag = document.RootElement; + + clientSdkFlags.Add(await GetClientSdkFlagAsync(flag, user)); + } + + return new ClientSdkPayload(eventType, user.KeyId, clientSdkFlags); + } + + public async Task GetServerSdkPayloadAsync(Guid envId, long timestamp) + { + var eventType = timestamp == 0 ? DataSyncEventTypes.Full : DataSyncEventTypes.Patch; + var featureFlags = new List(); + var segments = new List(); + + var flagsBytes = await _cacheService.GetFlagsAsync(envId, timestamp); + foreach (var flag in flagsBytes) + { + var jsonObject = JsonNode.Parse(flag)!.AsObject(); + jsonObject.Remove(""); + featureFlags.Add(jsonObject); + } + + var segmentsBytes = await _cacheService.GetSegmentsAsync(envId, timestamp); + foreach (var segment in segmentsBytes) + { + var jsonObject = JsonNode.Parse(segment)!.AsObject(); + segments.Add(jsonObject); + } + + return new ServerSdkPayload(eventType, featureFlags, segments); + } + public async Task GetFlagChangePayloadAsync(Connection connection, JsonElement flag) { if (connection.Type == ConnectionType.Client && connection.User == null) @@ -118,23 +159,6 @@ private async Task GetClientSdkFlagAsync(JsonElement flag, EndUse return new ClientSdkFlag(flag, userVariation, variations); } - private async Task GetClientSdkPayloadAsync(Guid envId, EndUser user, long timestamp) - { - var eventType = timestamp == 0 ? DataSyncEventTypes.Full : DataSyncEventTypes.Patch; - var flagsBytes = await _cacheService.GetFlagsAsync(envId, timestamp); - - var clientSdkFlags = new List(); - foreach (var flagBytes in flagsBytes) - { - using var document = JsonDocument.Parse(flagBytes); - var flag = document.RootElement; - - clientSdkFlags.Add(await GetClientSdkFlagAsync(flag, user)); - } - - return new ClientSdkPayload(eventType, user.KeyId, clientSdkFlags); - } - #endregion #region get server sdk payload @@ -157,28 +181,5 @@ private ServerSdkPayload GetServerSdkSegmentChangePayload(JsonElement segment) ); } - private async Task GetServerSdkPayloadAsync(Guid envId, long timestamp) - { - var eventType = timestamp == 0 ? DataSyncEventTypes.Full : DataSyncEventTypes.Patch; - var featureFlags = new List(); - var segments = new List(); - - var flagsBytes = await _cacheService.GetFlagsAsync(envId, timestamp); - foreach (var flag in flagsBytes) - { - var jsonObject = JsonNode.Parse(flag)!.AsObject(); - featureFlags.Add(jsonObject); - } - - var segmentsBytes = await _cacheService.GetSegmentsAsync(envId, timestamp); - foreach (var segment in segmentsBytes) - { - var jsonObject = JsonNode.Parse(segment)!.AsObject(); - segments.Add(jsonObject); - } - - return new ServerSdkPayload(eventType, featureFlags, segments); - } - #endregion } \ No newline at end of file