Skip to content

Commit

Permalink
Add AAI UserAgent
Browse files Browse the repository at this point in the history
  • Loading branch information
Swimburger committed May 30, 2024
1 parent 196eb9c commit 1e4e94f
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 1 deletion.
7 changes: 7 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,18 @@ src/main/java/com/assemblyai/api/resources/realtime/types/SessionTerminated.java

# Ignore ClientOptions to support custom timeouts for LeMUR.
src/main/java/com/assemblyai/api/AssemblyAIBuilder.java
src/main/java/com/assemblyai/api/core/Environment.java
src/main/java/com/assemblyai/api/core/ClientOptions.java
src/main/java/com/assemblyai/api/core/UserAgent.java
src/main/java/com/assemblyai/api/core/UserAgentInterceptor.java
src/main/java/com/assemblyai/api/core/UserAgentItem.java

sample-app/src/main/java/sample/App.java
sample-app/src/main/resources/

# Ignore tests
src/test

LICENSE
README.md

Expand Down
4 changes: 4 additions & 0 deletions sample-app/src/main/java/sample/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import com.assemblyai.api.AssemblyAI;
import com.assemblyai.api.RealtimeTranscriber;
import com.assemblyai.api.core.Environment;
import com.assemblyai.api.core.UserAgent;
import com.assemblyai.api.core.UserAgentItem;
import com.assemblyai.api.resources.files.types.UploadedFile;
import com.assemblyai.api.resources.lemur.requests.LemurTaskParams;
import com.assemblyai.api.resources.lemur.types.LemurTaskResponse;
Expand All @@ -15,6 +18,7 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/com/assemblyai/api/core/ClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import okhttp3.OkHttpClient;

import static com.assemblyai.api.core.Constants.SDK_VERSION;

public final class ClientOptions {
private final Environment environment;

Expand All @@ -30,7 +32,7 @@ private ClientOptions(
this.headers.putAll(new HashMap<String, String>() {
{
put("X-Fern-SDK-Name", "com.assemblyai.fern:api-sdk");
put("X-Fern-SDK-Version", "1.0.9");
put("X-Fern-SDK-Version", SDK_VERSION);
put("X-Fern-Language", "JAVA");
}
});
Expand Down Expand Up @@ -113,6 +115,7 @@ public Builder disableTimeouts() {

public ClientOptions build() {
OkHttpClient.Builder okhttpClientBuilder = new OkHttpClient.Builder()
.addInterceptor(new UserAgentInterceptor(environment))
.addInterceptor(new RetryInterceptor(3));
if (this.disableTimeouts) {
okhttpClientBuilder
Expand All @@ -124,4 +127,6 @@ public ClientOptions build() {
return new ClientOptions(environment, headers, headerSuppliers, okhttpClientBuilder.build());
}
}


}
5 changes: 5 additions & 0 deletions src/main/java/com/assemblyai/api/core/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.assemblyai.api.core;

public class Constants {
public static final String SDK_VERSION = "1.1.2";
}
23 changes: 23 additions & 0 deletions src/main/java/com/assemblyai/api/core/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
*/
package com.assemblyai.api.core;

import java.util.Optional;

public final class Environment {
public static final Environment DEFAULT = new Environment("https://api.assemblyai.com");

private final String url;
private UserAgent userAgent = UserAgent.getDefault();

private Environment(String url) {
this.url = url;
Expand All @@ -16,7 +19,27 @@ public String getUrl() {
return this.url;
}


public static Environment custom(String url) {
return new Environment(url);
}

public void updateUserAgent(UserAgent userAgent) {
// if incoming user agent is null, set to null
if (userAgent == null) {
this.userAgent = null;
return;
}
// if stored user agent is null, set new user agent
if (this.userAgent == null) {
this.userAgent = userAgent;
return;
}
// else, merge existing user agent with incoming user agent
this.userAgent = new UserAgent(this.userAgent, userAgent);
}

public Optional<UserAgent> getUserAgent() {
return Optional.ofNullable(this.userAgent);
}
}
94 changes: 94 additions & 0 deletions src/main/java/com/assemblyai/api/core/UserAgent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.assemblyai.api.core;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static com.assemblyai.api.core.Constants.SDK_VERSION;

public class UserAgent {
private static final UserAgent defaultUserAgent;

static {
defaultUserAgent = createDefaultUserAgent();
}

private final Map<String, UserAgentItem> userAgent;

public UserAgent(Map<String, UserAgentItem> userAgent) {
this.userAgent = userAgent;
}

public UserAgent(UserAgent a, UserAgent b) {
this.userAgent = UserAgent.merge(a.userAgent, b.userAgent);
}

public String toAssemblyAIUserAgentString() {
StringBuilder sb = new StringBuilder();
if (this.userAgent == null) {
return sb.toString();
}

sb.append(" AssemblyAI/1.0 (");
sb.append(
this.userAgent
.entrySet()
.stream()
.map(entry -> String.format(
"%s=%s/%s",
entry.getKey(),
entry.getValue().getName(),
entry.getValue().getVersion()
))
.collect(Collectors.joining(" "))
);
sb.append(")");
return sb.toString();
}

public static UserAgent getDefault(){
return defaultUserAgent;
}

private static UserAgent createDefaultUserAgent() {
HashMap<String, UserAgentItem> defaultUserAgent = new HashMap<>();
defaultUserAgent.put(
"sdk",
new UserAgentItem(
"Java",
SDK_VERSION
)
);
defaultUserAgent.put(
"runtime_env",
new UserAgentItem(
System.getProperty("java.runtime.name"),
System.getProperty("java.runtime.version")
)
);

return new UserAgent(defaultUserAgent);
}

private UserAgent merge(UserAgent other) {
return new UserAgent(UserAgent.merge(this.userAgent, other.userAgent));
}

private static Map<String, UserAgentItem> merge(Map<String, UserAgentItem> a, Map<String, UserAgentItem> b) {
Map<String, UserAgentItem> newUserAgent = new HashMap<>();

// user this user agent
newUserAgent.putAll(a);
// override with incoming user agent
newUserAgent.putAll(b);

// remove all null values
for (Map.Entry<String, UserAgentItem> entry : b.entrySet()) {
if (entry.getValue() == null) {
newUserAgent.remove(entry.getKey());
}
}
return newUserAgent;
}
}

49 changes: 49 additions & 0 deletions src/main/java/com/assemblyai/api/core/UserAgentInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.assemblyai.api.core;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.Optional;

public class UserAgentInterceptor implements Interceptor {
private final Environment environment;

public UserAgentInterceptor(Environment environment) {
this.environment = environment;
}

@NotNull
@Override
public Response intercept(@NotNull Chain chain) throws IOException {
Optional<UserAgent> userAgent = this.environment.getUserAgent();
if (!userAgent.isPresent()) {
return chain.proceed(chain.request());
}

Request originalRequest = chain.request();
String userAgentString = originalRequest.headers().get("User-Agent");
if (userAgentString != null) {
// if already contains AssemblyAI UA, skip
if (userAgentString.contains("AssemblyAI/")) {
return chain.proceed(chain.request());
}
} else {
userAgentString = "";
}

String assemblyAIUserAgentString = userAgent.get().toAssemblyAIUserAgentString();
// if AAI UA null or empty, skip
if (assemblyAIUserAgentString == null || assemblyAIUserAgentString.isEmpty()) {
return chain.proceed(chain.request());
}

userAgentString += " " + assemblyAIUserAgentString;
Request requestWithUserAgent = originalRequest.newBuilder()
.header("User-Agent", userAgentString)
.build();
return chain.proceed(requestWithUserAgent);
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/assemblyai/api/core/UserAgentItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.assemblyai.api.core;

public class UserAgentItem{
private final String name;
private final String version;

public UserAgentItem(String name, String version) {
this.name = name;
this.version = version;
}

public String getName() {
return name;
}

public String getVersion() {
return version;
}
}
109 changes: 109 additions & 0 deletions src/test/java/com/assemblyai/api/UserAgentTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.assemblyai.api;

import com.assemblyai.api.core.Environment;
import com.assemblyai.api.core.UserAgent;
import com.assemblyai.api.core.UserAgentItem;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Optional;

import static com.assemblyai.api.core.Constants.SDK_VERSION;

public final class UserAgentTest {
@Test
public void ShouldCreateDefaultUserAgent() {
UserAgent agent = UserAgent.getDefault();
assert agent != null;
String userAgentString = agent.toAssemblyAIUserAgentString();
assert userAgentString != null;
assert userAgentString.contains("AssemblyAI/1.0 (");
assert userAgentString.endsWith(")");
assert userAgentString.contains("sdk=Java/" + SDK_VERSION);
assert userAgentString.contains("runtime_env=OpenJDK Runtime Environment/");
}

@Test
public void ShouldUpdateUserAgentSdk() {
Environment env = Environment.DEFAULT;
env.updateUserAgent(new UserAgent(new HashMap<String, UserAgentItem>() {{
put("sdk", new UserAgentItem("Kotlin", "0.0"));
}}));

Optional<UserAgent> userAgent = env.getUserAgent();
assert userAgent.isPresent();
String userAgentString = userAgent.get().toAssemblyAIUserAgentString();
System.out.println(userAgentString);
assert userAgentString != null;
assert userAgentString.contains("AssemblyAI/1.0 (");
assert userAgentString.endsWith(")");
assert !userAgentString.contains("sdk=Java");
assert userAgentString.contains("sdk=Kotlin/0.0");
assert userAgentString.contains("runtime_env=OpenJDK Runtime Environment/");
}

@Test
public void ShouldAddUserAgentIntegration() {
Environment env = Environment.DEFAULT;
env.updateUserAgent(new UserAgent(new HashMap<String, UserAgentItem>() {{
put("integration", new UserAgentItem("Foo", "Bar"));
}}));

Optional<UserAgent> userAgent = env.getUserAgent();
assert userAgent.isPresent();
String userAgentString = userAgent.get().toAssemblyAIUserAgentString();
System.out.println(userAgentString);
assert userAgentString != null;
assert userAgentString.contains("AssemblyAI/1.0 (");
assert userAgentString.endsWith(")");
assert userAgentString.contains("integration=Foo/Bar");
assert userAgentString.contains("sdk=Java/" + SDK_VERSION);
assert userAgentString.contains("runtime_env=OpenJDK Runtime Environment/");
}

@Test
public void ShouldRemoveUserAgent() {
Environment env = Environment.DEFAULT;
env.updateUserAgent(null);

Optional<UserAgent> userAgent = env.getUserAgent();
assert !userAgent.isPresent();
}

@Test
public void ShouldReplaceUserAgent() {
Environment env = Environment.DEFAULT;
env.updateUserAgent(null);
env.updateUserAgent(new UserAgent(new HashMap<String, UserAgentItem>() {{
put("custom", new UserAgentItem("Foo", "Bar"));
}}));

Optional<UserAgent> userAgent = env.getUserAgent();
assert userAgent.isPresent();
String userAgentString = userAgent.get().toAssemblyAIUserAgentString();
System.out.println(userAgentString);
assert userAgentString != null;
assert userAgentString.contains("AssemblyAI/1.0 (");
assert userAgentString.endsWith(")");
assert userAgentString.contains("custom=Foo/Bar");
assert !userAgentString.contains("sdk");
assert !userAgentString.contains("runtime_env");
}

@Test
public void ShouldRemoveUserAgentItem() {
Environment env = Environment.DEFAULT;
env.updateUserAgent(new UserAgent(new HashMap<String, UserAgentItem>() {{
put("runtime_env", null);
}}));
Optional<UserAgent> userAgent = env.getUserAgent();
assert userAgent.isPresent();
String userAgentString = userAgent.get().toAssemblyAIUserAgentString();
System.out.println(userAgentString);
assert userAgentString != null;
assert userAgentString.contains("AssemblyAI/1.0 (");
assert userAgentString.endsWith(")");
assert userAgentString.contains("sdk=Java/" + SDK_VERSION);
assert !userAgentString.contains("runtime_env");
}
}

0 comments on commit 1e4e94f

Please sign in to comment.