Skip to content

Commit c472320

Browse files
committed
resolve mode for remote and local resolve
1 parent 25bce7b commit c472320

File tree

14 files changed

+459
-66
lines changed

14 files changed

+459
-66
lines changed

demo/pom.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<groupId>com.confidence.demo</groupId>
7+
<artifactId>confidence-demo-app</artifactId>
8+
<version>1.0-SNAPSHOT</version>
9+
10+
<dependencies>
11+
<!-- Add your local dependency here -->
12+
<dependency>
13+
<groupId>com.spotify.confidence</groupId>
14+
<artifactId>confidence-sdk-java</artifactId>
15+
<scope>system</scope>
16+
<systemPath>[PATH_TO_JAR]</systemPath>
17+
<version>0.0.16-SNAPSHOT</version>
18+
</dependency>
19+
</dependencies>
20+
</project>
21+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.confidence.demo.app;
2+
3+
import com.spotify.confidence.Confidence;
4+
import com.spotify.confidence.ConfidenceValue;
5+
import com.spotify.confidence.LocalResolve;
6+
import com.spotify.confidence.ResolveMode;
7+
8+
import java.util.Map;
9+
10+
public class Main {
11+
public static void main(String[] args) {
12+
LocalResolve localResolve = new LocalResolve("API_KEY");
13+
final Confidence confidence = Confidence.builder("API_KEY", localResolve).build();
14+
final ConfidenceValue.Struct propertyValue =
15+
confidence
16+
.withContext(Map.of("targeting_key", ConfidenceValue.of("SE")))
17+
.getValue("roug", ConfidenceValue.Struct.builder().build());
18+
System.out.println(propertyValue);
19+
confidence.track("navigate", ConfidenceValue.of(Map.of("field", ConfidenceValue.of("data"))));
20+
}
21+
}

openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,14 @@ public ConfidenceFeatureProvider(Confidence confidence) {
5151
*/
5252
@Deprecated()
5353
public ConfidenceFeatureProvider(String clientSecret, ManagedChannel managedChannel) {
54-
this(Confidence.builder(clientSecret).flagResolverManagedChannel(managedChannel).build());
54+
this(
55+
Confidence.builder(
56+
clientSecret,
57+
RemoteResolve.builder()
58+
.flagResolverManagedChannel(managedChannel)
59+
.setClientSecret(clientSecret)
60+
.build())
61+
.build());
5562
}
5663

5764
/**

sdk-java/pom.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@
2121
</exclusion>
2222
</exclusions>
2323
</dependency>
24+
<dependency>
25+
<groupId>com.dylibso.chicory</groupId>
26+
<artifactId>runtime</artifactId>
27+
<version>1.4.0</version>
28+
</dependency>
29+
<dependency>
30+
<groupId>com.dylibso.chicory</groupId>
31+
<artifactId>compiler</artifactId>
32+
<version>1.4.0</version>
33+
</dependency>
2434
<dependency>
2535
<groupId>com.google.protobuf</groupId>
2636
<artifactId>protobuf-java-util</artifactId>
@@ -84,6 +94,24 @@
8494
</configuration>
8595
</plugin>
8696
</plugins>
97+
<resources>
98+
<resource>
99+
<directory>src/main/resources</directory>
100+
<filtering>true</filtering>
101+
<excludes>
102+
<exclude>**/*.wasm</exclude>
103+
<exclude>**/*.pb</exclude>
104+
</excludes>
105+
</resource>
106+
<resource>
107+
<directory>src/main/resources</directory>
108+
<filtering>false</filtering>
109+
<includes>
110+
<include>**/*.wasm</include>
111+
<include>**/*.pb</include>
112+
</includes>
113+
</resource>
114+
</resources>
87115
</build>
88116

89117
</project>

sdk-java/src/main/java/com/spotify/confidence/Confidence.java

Lines changed: 15 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,14 @@ static Confidence create(
244244
new ClientDelegate(closer, flagResolverClient, eventSenderEngine, clientSecret));
245245
}
246246

247+
public static Confidence.Builder builder(String clientSecret, ResolveMode resolveMode) {
248+
return new Confidence.Builder(clientSecret, resolveMode);
249+
}
250+
247251
public static Confidence.Builder builder(String clientSecret) {
248-
return new Confidence.Builder(clientSecret);
252+
final var remoteResolve =
253+
RemoteResolve.builder().setClientSecret(clientSecret).setResolveDeadlineMs(10_000).build();
254+
return new Confidence.Builder(clientSecret, remoteResolve);
249255
}
250256

251257
static class ClientDelegate implements FlagResolverClient, EventSenderEngine {
@@ -352,86 +358,32 @@ public void flush() {
352358

353359
public static class Builder {
354360
private final String clientSecret;
361+
private final ResolveMode resolveMode;
355362
private final Closer closer = Closer.create();
356-
357-
private final ManagedChannel DEFAULT_CHANNEL =
358-
ManagedChannelBuilder.forAddress("edge-grpc.spotify.com", 443)
359-
.keepAliveTime(Duration.ofMinutes(5).getSeconds(), TimeUnit.SECONDS)
360-
.build();
361-
private ManagedChannel flagResolverManagedChannel = DEFAULT_CHANNEL;
362-
private boolean disableTelemetry = false;
363-
private boolean isProvider = false;
364-
private int resolveDeadlineMs = 10_000;
365363
private int eventSenderDeadlineMs = 5_000;
366364

367-
public Builder(@Nonnull String clientSecret) {
365+
public Builder(@Nonnull String clientSecret, ResolveMode resolveMode) {
368366
this.clientSecret = clientSecret;
369-
registerChannelForShutdown(DEFAULT_CHANNEL);
370-
}
371-
372-
public Builder resolveDeadlineMs(int resolveDeadlineMs) {
373-
this.resolveDeadlineMs = resolveDeadlineMs;
374-
return this;
367+
this.resolveMode = resolveMode;
375368
}
376369

377370
public Builder eventSenderDeadlineMs(int eventSenderDeadlineMs) {
378371
this.eventSenderDeadlineMs = eventSenderDeadlineMs;
379372
return this;
380373
}
381374

382-
public Builder flagResolverManagedChannel(String host, int port) {
383-
this.flagResolverManagedChannel =
384-
ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
385-
registerChannelForShutdown(this.flagResolverManagedChannel);
386-
return this;
387-
}
388-
389-
public Builder flagResolverManagedChannel(ManagedChannel managedChannel) {
390-
this.flagResolverManagedChannel = managedChannel;
391-
return this;
392-
}
393-
394-
public Builder disableTelemetry(boolean disableTelemetry) {
395-
this.disableTelemetry = disableTelemetry;
396-
return this;
397-
}
398-
399-
public Confidence buildForProvider() {
400-
this.isProvider = true;
401-
return build();
402-
}
403-
404375
public Confidence build() {
405-
final FlagResolverClient flagResolverClient;
406-
final Telemetry telemetry = disableTelemetry ? null : new Telemetry(isProvider);
407-
final TelemetryClientInterceptor telemetryInterceptor =
408-
new TelemetryClientInterceptor(telemetry);
409-
final GrpcFlagResolver flagResolver =
410-
new GrpcFlagResolver(
411-
clientSecret, flagResolverManagedChannel, telemetryInterceptor, resolveDeadlineMs);
412-
413-
flagResolverClient = new FlagResolverClientImpl(flagResolver, telemetry);
376+
final ManagedChannel DEFAULT_CHANNEL =
377+
ManagedChannelBuilder.forAddress("edge-grpc.spotify.com", 443)
378+
.keepAliveTime(Duration.ofMinutes(5).getSeconds(), TimeUnit.SECONDS)
379+
.build();
414380

415381
final EventSenderEngine eventSenderEngine =
416382
new EventSenderEngineImpl(
417383
clientSecret, DEFAULT_CHANNEL, Instant::now, eventSenderDeadlineMs);
418-
closer.register(flagResolverClient);
419384
closer.register(eventSenderEngine);
420385
return new RootInstance(
421-
new ClientDelegate(closer, flagResolverClient, eventSenderEngine, clientSecret));
422-
}
423-
424-
private void registerChannelForShutdown(ManagedChannel channel) {
425-
this.closer.register(
426-
() -> {
427-
channel.shutdown();
428-
try {
429-
channel.awaitTermination(10, TimeUnit.SECONDS);
430-
} catch (InterruptedException e) {
431-
Thread.currentThread().interrupt();
432-
channel.shutdownNow();
433-
}
434-
});
386+
new ClientDelegate(closer, resolveMode, eventSenderEngine, clientSecret));
435387
}
436388
}
437389
}

sdk-java/src/main/java/com/spotify/confidence/FlagResolverClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
import java.io.Closeable;
55
import java.util.concurrent.CompletableFuture;
66

7-
interface FlagResolverClient extends Closeable {
7+
public interface FlagResolverClient extends Closeable {
88
CompletableFuture<ResolveFlagsResponse> resolveFlags(String flag, ConfidenceValue.Struct context);
99
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.spotify.confidence;
2+
3+
import com.dylibso.chicory.wasm.Parser;
4+
import com.dylibso.chicory.wasm.WasmModule;
5+
import com.google.protobuf.Struct;
6+
import com.spotify.confidence.shaded.flags.resolver.v1.ResolveFlagsRequest;
7+
import com.spotify.confidence.shaded.flags.resolver.v1.ResolveFlagsResponse;
8+
import java.io.IOException;
9+
import java.io.InputStream;
10+
import java.util.concurrent.CompletableFuture;
11+
12+
public class LocalResolve implements ResolveMode {
13+
private final LocalResolverApi localResolverApi;
14+
private final String clientSecret;
15+
16+
@Override
17+
public void close() {}
18+
19+
public LocalResolve(String clientSecret) {
20+
this.clientSecret = clientSecret;
21+
22+
// Load WASM module from resources
23+
try (InputStream wasmStream =
24+
getClass().getClassLoader().getResourceAsStream("wasm/rust_guest.wasm")) {
25+
if (wasmStream == null) {
26+
throw new RuntimeException("Could not find rust_guest.wasm in resources");
27+
}
28+
WasmModule module = Parser.parse(wasmStream);
29+
this.localResolverApi = new LocalResolverApi(module);
30+
setResolverState();
31+
} catch (IOException e) {
32+
throw new RuntimeException("Failed to load WASM module", e);
33+
}
34+
}
35+
36+
private void setResolverState() {
37+
// Load resolver state from resources
38+
try (InputStream stateStream =
39+
getClass().getClassLoader().getResourceAsStream("state/resolver_state.pb")) {
40+
if (stateStream == null) {
41+
throw new RuntimeException("Could not find resolver_state.pb in resources");
42+
}
43+
byte[] resolveState = stateStream.readAllBytes();
44+
this.localResolverApi.setResolverState(resolveState);
45+
} catch (IOException e) {
46+
throw new RuntimeException("Failed to load resolver state", e);
47+
}
48+
}
49+
50+
@Override
51+
public CompletableFuture<ResolveFlagsResponse> resolveFlags(
52+
String flag, ConfidenceValue.Struct context) {
53+
final var response =
54+
localResolverApi.resolve(
55+
ResolveFlagsRequest.newBuilder()
56+
.setClientSecret(clientSecret)
57+
.setApply(false)
58+
.setEvaluationContext(Struct.newBuilder().putAllFields(context.asProtoMap()))
59+
.addFlags(flag)
60+
.build());
61+
return CompletableFuture.completedFuture(response);
62+
}
63+
}

0 commit comments

Comments
 (0)