Skip to content

Commit

Permalink
sdkConfig + LastModified
Browse files Browse the repository at this point in the history
  • Loading branch information
JamieSinn committed Jun 17, 2024
1 parent 6128289 commit c11830a
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 9 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

def wasmResourcePath = "$projectDir/src/main/resources"
def wasmVersion = "1.21.0"
def wasmVersion = "1.23.0"
def wasmUrl = "https://unpkg.com/@devcycle/bucketing-assembly-script@$wasmVersion/build/bucketing-lib.release.wasm"
task downloadDVCBucketingWASM(type: Download) {
src wasmUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public interface IDevCycleApi {
*/
@Headers({"Content-Type:application/json"})
@GET("config/v1/server/{sdkToken}.json")
Call<ProjectConfig> getConfig(@Path("sdkToken") String sdkToken, @Header("If-None-Match") String etag);
Call<ProjectConfig> getConfig(@Path("sdkToken") String sdkToken, @Header("If-None-Match") String etag, @Header("If-Modified-Since") String lastModified);

/**
* Post events to DevCycle for user
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ public DevCycleLocalClient(String sdkKey, DevCycleLocalOptions dvcOptions) {

localBucketing.setPlatformData(PlatformData.builder().build().toString());

configManager = new EnvironmentConfigManager(sdkKey, localBucketing, dvcOptions);
this.sdkKey = sdkKey;
try {
eventQueueManager = new EventQueueManager(sdkKey, localBucketing, dvcOptions);
} catch (Exception e) {
DevCycleLogger.error("Error creating event queue due to error: " + e.getMessage());
}
configManager = new EnvironmentConfigManager(sdkKey, localBucketing, eventQueueManager, dvcOptions);
this.openFeatureProvider = new DevCycleProvider(this);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import io.github.kawamuray.wasmtime.Module;
import io.github.kawamuray.wasmtime.*;
import lombok.Getter;

import java.io.IOException;
import java.io.InputStream;
Expand All @@ -30,6 +31,8 @@ public class LocalBucketing {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private final int WASM_OBJECT_ID_STRING = 1;
private final int WASM_OBJECT_ID_UINT8ARRAY = 9;
@Getter
private final String clientUUID = UUID.randomUUID().toString();
Store<Void> store; // WASM compilation environment
Linker linker; // used to read/write to WASM
AtomicReference<Memory> memRef; // reference to start of WASM's memory
Expand Down Expand Up @@ -263,11 +266,12 @@ public synchronized byte[] getVariableForUserProtobuf(byte[] serializedParams) {
public synchronized void initEventQueue(String sdkKey, String options) {
unpinAll();
int sdkKeyAddress = getSDKKeyAddress(sdkKey);
int clientUUIDAddress = getSDKKeyAddress(clientUUID);
int optionsAddress = newWasmString(options);

Func initEventQueuePtr = linker.get(store, "", "initEventQueue").get().func();
WasmFunctions.Consumer2<Integer, Integer> fn = WasmFunctions.consumer(store, initEventQueuePtr, I32, I32);
fn.accept(sdkKeyAddress, optionsAddress);
WasmFunctions.Consumer3<Integer, Integer, Integer> fn = WasmFunctions.consumer(store, initEventQueuePtr, I32, I32, I32);
fn.accept(sdkKeyAddress, clientUUIDAddress, optionsAddress);
}

public synchronized void queueEvent(String sdkKey, String user, String event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,21 @@ public final class EnvironmentConfigManager {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new DaemonThreadFactory());
private final IDevCycleApi configApiClient;
private final LocalBucketing localBucketing;
private final EventQueueManager eventQueueManager;

private ProjectConfig config;
private String configETag = "";

private String configLastModified = "";

private final String sdkKey;
private final int pollingIntervalMS;
private boolean pollingEnabled = true;

public EnvironmentConfigManager(String sdkKey, LocalBucketing localBucketing, DevCycleLocalOptions options) {
public EnvironmentConfigManager(String sdkKey, LocalBucketing localBucketing, EventQueueManager eventQueue, DevCycleLocalOptions options) {
this.sdkKey = sdkKey;
this.localBucketing = localBucketing;

this.eventQueueManager = eventQueue;
configApiClient = new DevCycleLocalApiClient(sdkKey, options).initialize();

int configPollingIntervalMS = options.getConfigPollingIntervalMS();
Expand Down Expand Up @@ -69,7 +72,7 @@ public boolean isConfigInitialized() {
}

private ProjectConfig getConfig() throws DevCycleException {
Call<ProjectConfig> config = this.configApiClient.getConfig(this.sdkKey, this.configETag);
Call<ProjectConfig> config = this.configApiClient.getConfig(this.sdkKey, this.configETag, this.configLastModified);
this.config = getResponseWithRetries(config, 1);
return this.config;
}
Expand Down Expand Up @@ -129,6 +132,8 @@ private ProjectConfig getConfigResponse(Call<ProjectConfig> call) throws DevCycl

if (response.isSuccessful()) {
String currentETag = response.headers().get("ETag");
String lastModified = response.headers().get("Last-Modified");

ProjectConfig config = response.body();
try {
ObjectMapper mapper = new ObjectMapper();
Expand All @@ -143,6 +148,12 @@ private ProjectConfig getConfigResponse(Call<ProjectConfig> call) throws DevCycl
}
}
this.configETag = currentETag;
this.configLastModified = lastModified;
try {
this.eventQueueManager.queueSDKConfigEvent(call.request(), response);
} catch (Exception e) {
// Explicitly ignore - best effort.
}
return response.body();
} else if (httpResponseCode == HttpResponseCode.NOT_MODIFIED) {
DevCycleLogger.debug("Config not modified, using cache, etag: " + this.configETag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.devcycle.sdk.server.common.model.DevCycleEvent;
import com.devcycle.sdk.server.common.model.DevCycleResponse;
import com.devcycle.sdk.server.common.model.DevCycleUser;
import com.devcycle.sdk.server.common.model.ProjectConfig;
import com.devcycle.sdk.server.local.api.DevCycleLocalEventsApiClient;
import com.devcycle.sdk.server.local.bucketing.LocalBucketing;
import com.devcycle.sdk.server.local.model.BucketedUserConfig;
Expand All @@ -13,11 +14,15 @@
import com.devcycle.sdk.server.local.model.FlushPayload;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.Request;
import retrofit2.Call;
import retrofit2.Response;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -105,6 +110,36 @@ public void queueEvent(DevCycleUser user, DevCycleEvent event) throws Exception
this.localBucketing.queueEvent(this.sdkKey, OBJECT_MAPPER.writeValueAsString(user), OBJECT_MAPPER.writeValueAsString(event));
}

public void queueSDKConfigEvent(Request req, Response<ProjectConfig> response) throws Exception {
DevCycleUser user = new DevCycleUser();
user.setUserId(localBucketing.getClientUUID() + "@" + InetAddress.getLocalHost().getHostName());
DevCycleEvent event = new DevCycleEvent();
event.setType("sdkConfig");
event.setTarget(req.url().toString());

try(okhttp3.Response res = response.raw()) {
if (res.isSuccessful()) {
event.setValue(BigDecimal.valueOf(res.networkResponse().receivedResponseAtMillis() - res.networkResponse().sentRequestAtMillis()));
} else {
event.setValue(BigDecimal.valueOf(-1));
}
event.setMetaData(Map.of(
"clientUUID", localBucketing.getClientUUID(),
"reqEtag", req.header("If-None-Match"),
"reqLastModified", req.header("If-Modified-Since"),
"resEtag", res.header("etag"),
"resLastModified", res.header("Last-Modified"),
"resRayId", res.header("cf-ray"),
"resStatus", response.code(),
"errMsg", response.code() != 200 && response.code() != 304 ? response.message() : null,
"sseConnected", null));

} catch (Exception e) {
event.setValue(BigDecimal.valueOf(-1));
}
queueEvent(user, event);
}

/**
* Queue DevCycleEvent that can be aggregated together, where multiple calls are aggregated
* by incrementing the 'value' field.
Expand Down
Binary file modified src/main/resources/bucketing-lib.release.wasm
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public Call<DevCycleResponse> track(DevCycleUserAndEvents userAndEvents, Boolean
}

@Override
public Call<ProjectConfig> getConfig(String sdkToken, String etag) {
public Call<ProjectConfig> getConfig(String sdkToken, String etag, String lastModified) {
// TODO Auto-generated method stub
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public Map<String, String> getHeaders() {
Map<String, String> headers = new HashMap<>();
headers.put("Oauth-Token", "test-token");
headers.put("Custom-Meta-Data", "some information the developer wants send");
headers.put("Authorization", "Custom auth header");
return headers;
}

Expand Down

0 comments on commit c11830a

Please sign in to comment.