From 0345d263effba8171af1bcdf5dbab7d0c69bd108 Mon Sep 17 00:00:00 2001 From: Jonathan Breedlove Date: Fri, 20 Sep 2024 11:28:20 -0700 Subject: [PATCH] Implementation of generated telemetry client (#25) --- plugin/.classpath | 53 ++-- plugin/META-INF/MANIFEST.MF | 36 +++ plugin/build.properties | 3 +- plugin/codegen-resources/service-2.json | 258 ++++++++++++++++++ plugin/pom.xml | 64 +++++ .../AwsCognitoCredentialsProvider.java | 39 +++ .../amazonq/telemetry/TelemetryService.java | 51 ++++ 7 files changed, 476 insertions(+), 28 deletions(-) create mode 100644 plugin/codegen-resources/service-2.json create mode 100644 plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/AwsCognitoCredentialsProvider.java create mode 100644 plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/TelemetryService.java diff --git a/plugin/.classpath b/plugin/.classpath index cb625adc..d5b83737 100644 --- a/plugin/.classpath +++ b/plugin/.classpath @@ -1,29 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugin/META-INF/MANIFEST.MF b/plugin/META-INF/MANIFEST.MF index 1b5c738f..48350943 100644 --- a/plugin/META-INF/MANIFEST.MF +++ b/plugin/META-INF/MANIFEST.MF @@ -21,6 +21,11 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.31.0", org.eclipse.mylyn.commons.ui;bundle-version="4.2.0" Bundle-Classpath: ., target/dependency/animal-sniffer-annotations-1.9.jar, + target/dependency/annotations-2.25.33.jar, + target/dependency/apache-client-2.25.33.jar, + target/dependency/auth-2.25.33.jar, + target/dependency/aws-core-2.25.33.jar, + target/dependency/aws-json-protocol-2.25.33.jar, target/dependency/batik-constants-1.17.jar, target/dependency/batik-css-1.17.jar, target/dependency/batik-i18n-1.17.jar, @@ -30,18 +35,28 @@ Bundle-Classpath: ., target/dependency/bcprov-jdk18on-1.78.1.jar, target/dependency/bcutil-jdk18on-1.78.1.jar, target/dependency/checker-qual-3.42.0.jar, + target/dependency/checksums-2.25.33.jar, + target/dependency/checksums-spi-2.25.33.jar, + target/dependency/cognitoidentity-2.25.33.jar, target/dependency/commons-codec-1.15.jar, target/dependency/commons-collections4-4.4.jar, target/dependency/commons-io-2.16.1.jar, target/dependency/commons-lang3-3.14.0.jar, target/dependency/commons-logging-1.2.jar, + target/dependency/endpoints-spi-2.25.33.jar, target/dependency/error_prone_annotations-2.27.0.jar, + target/dependency/eventstream-1.0.1.jar, target/dependency/failureaccess-1.0.2.jar, target/dependency/gson-2.11.0.jar, target/dependency/guava-33.2.0-jre.jar, + target/dependency/http-auth-2.25.33.jar, + target/dependency/http-auth-aws-2.25.33.jar, + target/dependency/http-auth-spi-2.25.33.jar, + target/dependency/http-client-spi-2.25.33.jar, target/dependency/httpclient-4.5.13.jar, target/dependency/httpcore-4.4.13.jar, target/dependency/icu4j-75.1.jar, + target/dependency/identity-spi-2.25.33.jar, target/dependency/j2objc-annotations-3.0.0.jar, target/dependency/jackson-annotations-2.17.1.jar, target/dependency/jackson-core-2.17.1.jar, @@ -50,9 +65,22 @@ Bundle-Classpath: ., target/dependency/jakarta.inject-api-2.0.1.jar, target/dependency/jna-5.14.0.jar, target/dependency/jna-platform-5.14.0.jar, + target/dependency/json-utils-2.25.33.jar, target/dependency/jsoup-1.17.2.jar, target/dependency/jsr305-3.0.2.jar, target/dependency/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar, + target/dependency/metrics-spi-2.25.33.jar, + target/dependency/netty-buffer-4.1.108.Final.jar, + target/dependency/netty-codec-4.1.108.Final.jar, + target/dependency/netty-codec-http-4.1.108.Final.jar, + target/dependency/netty-codec-http2-4.1.108.Final.jar, + target/dependency/netty-common-4.1.108.Final.jar, + target/dependency/netty-handler-4.1.108.Final.jar, + target/dependency/netty-nio-client-2.25.33.jar, + target/dependency/netty-resolver-4.1.108.Final.jar, + target/dependency/netty-transport-4.1.108.Final.jar, + target/dependency/netty-transport-classes-epoll-4.1.108.Final.jar, + target/dependency/netty-transport-native-unix-common-4.1.108.Final.jar, target/dependency/org.apache.felix.scr-2.2.10.jar, target/dependency/org.eclipse.lsp4j-0.23.1.jar, target/dependency/org.eclipse.lsp4j.jsonrpc-0.23.1.jar, @@ -64,6 +92,14 @@ Bundle-Classpath: ., target/dependency/org.osgi.util.function-1.2.0.jar, target/dependency/org.osgi.util.promise-1.3.0.jar, target/dependency/osgi.annotation-8.1.0.jar, + target/dependency/profiles-2.25.33.jar, + target/dependency/protocol-core-2.25.33.jar, + target/dependency/reactive-streams-1.0.4.jar, + target/dependency/regions-2.25.33.jar, + target/dependency/sdk-core-2.25.33.jar, + target/dependency/slf4j-api-1.7.30.jar, + target/dependency/third-party-jackson-core-2.25.33.jar, + target/dependency/utils-2.25.33.jar, target/dependency/xml-apis-ext-1.3.04.jar, target/dependency/xmlgraphics-commons-2.9.jar, target/dependency/xz-1.9.jar diff --git a/plugin/build.properties b/plugin/build.properties index 05db5eb7..945624d1 100644 --- a/plugin/build.properties +++ b/plugin/build.properties @@ -1,8 +1,7 @@ -source.. = src/ +source.. = src/, target/generated-sources output.. = target/classes bin.includes = plugin.xml,\ META-INF/,\ - .,\ icons/,\ target/classes/,\ webview/build/,\ diff --git a/plugin/codegen-resources/service-2.json b/plugin/codegen-resources/service-2.json new file mode 100644 index 00000000..14d3ab7f --- /dev/null +++ b/plugin/codegen-resources/service-2.json @@ -0,0 +1,258 @@ +{ + "version":"2.0", + "metadata":{ + "apiVersion":"2017-07-25", + "endpointPrefix":"client-telemetry", + "jsonVersion":"1.1", + "protocol":"rest-json", + "serviceAbbreviation":"ToolkitTelemetry", + "serviceFullName":"A beautiful and amazing ToolkitTelemetry", + "serviceId":"ToolkitTelemetry", + "signatureVersion":"v4", + "signingName":"execute-api" + }, + "operations":{ + "PostErrorReport":{ + "name":"PostErrorReport", + "http":{ + "method":"POST", + "requestUri":"/errorReport" + }, + "input":{"shape":"PostErrorReportRequest"} + }, + "PostFeedback":{ + "name":"PostFeedback", + "http":{ + "method":"POST", + "requestUri":"/feedback" + }, + "input":{"shape":"PostFeedbackRequest"} + }, + "PostMetrics":{ + "name":"PostMetrics", + "http":{ + "method":"POST", + "requestUri":"/metrics" + }, + "input":{"shape":"PostMetricsRequest"} + } + }, + "shapes":{ + "AWSProduct":{ + "type":"string", + "enum":[ + "canary", + "AWS Toolkit For JetBrains", + "AWS Toolkit For Eclipse", + "AWS Toolkit For VisualStudio", + "AWS Toolkit For VS Code", + "Amazon Q For JetBrains", + "Amazon Q For VS Code", + "Amazon Q For Eclipse" + ] + }, + "AWSProductVersion":{ + "type":"string", + "pattern":"^[\\w+-.]{1,512}$" + }, + "ClientID":{ + "type":"string", + "pattern":"^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$" + }, + "Command":{ + "type":"string", + "max":2000 + }, + "Comment":{ + "type":"string", + "max":2000 + }, + "ComputeEnv":{ + "type":"string", + "enum":[ + "cloud9", + "cloud9-codecatalyst", + "cloud9-ec2", + "codecatalyst", + "ec2", + "local", + "sagemaker", + "ssh", + "test", + "web", + "wsl", + "other" + ] + }, + "Datapoint":{ + "type":"double", + "min":0 + }, + "Email":{ + "type":"string", + "pattern":"^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$" + }, + "EpochTimestamp":{ + "type":"long", + "min":0 + }, + "ErrorDetails":{ + "type":"structure", + "required":[ + "Command", + "EpochTimestamp", + "Type", + "StackTrace" + ], + "members":{ + "Command":{"shape":"Command"}, + "EpochTimestamp":{"shape":"EpochTimestamp"}, + "Type":{"shape":"Type"}, + "Message":{"shape":"Message"}, + "StackTrace":{"shape":"StackTrace"} + } + }, + "Key":{ + "type":"string", + "pattern":"^\\w[\\w\\.]{0,149}$" + }, + "Message":{ + "type":"string", + "max":2048 + }, + "Metadata":{ + "type":"list", + "member":{"shape":"MetadataEntry"} + }, + "MetadataEntry":{ + "type":"structure", + "members":{ + "Key":{"shape":"Key"}, + "Value":{"shape":"Value"} + } + }, + "MetricData":{ + "type":"list", + "member":{"shape":"MetricDatum"}, + "max":20, + "min":1 + }, + "MetricDatum":{ + "type":"structure", + "required":[ + "MetricName", + "EpochTimestamp", + "Unit", + "Value" + ], + "members":{ + "MetricName":{"shape":"MetricName"}, + "EpochTimestamp":{"shape":"EpochTimestamp"}, + "Unit":{"shape":"Unit"}, + "Value":{"shape":"Datapoint"}, + "Metadata":{"shape":"Metadata"}, + "Passive":{"shape":"Passive"} + } + }, + "MetricName":{ + "type":"string", + "pattern":"^[\\w+-.:]{1,255}$" + }, + "Passive":{"type":"boolean"}, + "PostErrorReportRequest":{ + "type":"structure", + "required":[ + "AWSProduct", + "AWSProductVersion", + "ErrorDetails" + ], + "members":{ + "AWSProduct":{"shape":"AWSProduct"}, + "AWSProductVersion":{"shape":"AWSProductVersion"}, + "Metadata":{"shape":"Metadata"}, + "Userdata":{"shape":"Userdata"}, + "ErrorDetails":{"shape":"ErrorDetails"} + } + }, + "PostFeedbackRequest":{ + "type":"structure", + "required":[ + "AWSProduct", + "AWSProductVersion", + "ParentProduct", + "ParentProductVersion", + "Sentiment", + "Comment" + ], + "members":{ + "AWSProduct":{"shape":"AWSProduct"}, + "AWSProductVersion":{"shape":"AWSProductVersion"}, + "OS":{"shape":"Value"}, + "OSVersion":{"shape":"Value"}, + "ComputeEnv": {"shape":"ComputeEnv"}, + "ParentProduct":{"shape":"Value"}, + "ParentProductVersion":{"shape":"Value"}, + "Metadata":{"shape":"Metadata"}, + "Sentiment":{"shape":"Sentiment"}, + "Comment":{"shape":"Comment"} + } + }, + "PostMetricsRequest":{ + "type":"structure", + "required":[ + "AWSProduct", + "AWSProductVersion", + "ClientID", + "MetricData" + ], + "members":{ + "AWSProduct":{"shape":"AWSProduct"}, + "AWSProductVersion":{"shape":"AWSProductVersion"}, + "ClientID":{"shape":"ClientID"}, + "OS":{"shape":"Value"}, + "OSArchitecture":{"shape":"Value"}, + "OSVersion":{"shape":"Value"}, + "ComputeEnv": {"shape":"ComputeEnv"}, + "ParentProduct":{"shape":"Value"}, + "ParentProductVersion":{"shape":"Value"}, + "MetricData":{"shape":"MetricData"} + } + }, + "Sentiment":{ + "type":"string", + "enum":[ + "Positive", + "Negative" + ] + }, + "StackTrace":{ + "type":"string", + "max":16384 + }, + "Type":{ + "type":"string", + "max":1024 + }, + "Unit":{ + "type":"string", + "enum":[ + "Milliseconds", + "Bytes", + "Percent", + "Count", + "None" + ] + }, + "Userdata":{ + "type":"structure", + "members":{ + "Email":{"shape":"Email"}, + "Comment":{"shape":"Comment"} + } + }, + "Value":{ + "type":"string", + "max":65536 + } + } +} \ No newline at end of file diff --git a/plugin/pom.xml b/plugin/pom.xml index f59cd2c5..3d5a8921 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -76,6 +76,26 @@ commons-codec 1.15 + + software.amazon.awssdk + aws-json-protocol + ${aws.java.sdk.version} + + + software.amazon.awssdk + cognitoidentity + ${aws.java.sdk.version} + + + software.amazon.awssdk + auth + ${aws.java.sdk.version} + + + software.amazon.awssdk + apache-client + ${aws.java.sdk.version} + org.junit.jupiter junit-jupiter @@ -194,6 +214,7 @@ true true false + src/**/*.java check @@ -276,6 +297,49 @@ + + software.amazon.awssdk + codegen-maven-plugin + ${aws.java.sdk.version} + + + generate-telemetry-client + generate-sources + + generate + + + + + ${project.basedir}/codegen-resources/ + ${project.build.directory} + false + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + move-generated-files + process-sources + + run + + + + + + + + + + + + + + diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/AwsCognitoCredentialsProvider.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/AwsCognitoCredentialsProvider.java new file mode 100644 index 00000000..fda76f28 --- /dev/null +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/AwsCognitoCredentialsProvider.java @@ -0,0 +1,39 @@ +// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.eclipse.amazonq.telemetry; + +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; +import software.amazon.awssdk.services.cognitoidentity.CognitoIdentityClient; +import software.amazon.awssdk.services.cognitoidentity.model.GetCredentialsForIdentityRequest; +import software.amazon.awssdk.services.cognitoidentity.model.GetCredentialsForIdentityResponse; +import software.amazon.awssdk.services.cognitoidentity.model.GetIdRequest; +import software.amazon.awssdk.services.cognitoidentity.model.GetIdResponse; + +public class AwsCognitoCredentialsProvider implements AwsCredentialsProvider { + private final String identityPoolId; + private final CognitoIdentityClient cognitoIdentityClient; + + public AwsCognitoCredentialsProvider(final String identityPoolId, final CognitoIdentityClient cognitoIdentityClient) { + this.identityPoolId = identityPoolId; + this.cognitoIdentityClient = cognitoIdentityClient; + } + + @Override + public final AwsSessionCredentials resolveCredentials() { + GetIdResponse getIdResponse = cognitoIdentityClient.getId(GetIdRequest.builder() + .identityPoolId(identityPoolId) + .build()); + + GetCredentialsForIdentityResponse getCredentialsResponse = cognitoIdentityClient.getCredentialsForIdentity(GetCredentialsForIdentityRequest.builder() + .identityId(getIdResponse.identityId()) + .build()); + + return AwsSessionCredentials.create( + getCredentialsResponse.credentials().accessKeyId(), + getCredentialsResponse.credentials().secretKey(), + getCredentialsResponse.credentials().sessionToken() + ); + } +} diff --git a/plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/TelemetryService.java b/plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/TelemetryService.java new file mode 100644 index 00000000..8242ae76 --- /dev/null +++ b/plugin/src/software/aws/toolkits/eclipse/amazonq/telemetry/TelemetryService.java @@ -0,0 +1,51 @@ +// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package software.aws.toolkits.eclipse.amazonq.telemetry; + +import java.io.InputStream; +import java.net.URI; + +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.http.apache.ApacheHttpClient; +import software.amazon.awssdk.profiles.ProfileFile; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.cognitoidentity.CognitoIdentityClient; +import software.amazon.awssdk.services.toolkittelemetry.ToolkitTelemetryClient; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; + +public final class TelemetryService { + private static final ToolkitTelemetryClient CLIENT = createDefaultTelemetryClient(); + private static final Region TELEMETRY_REGION = Region.US_EAST_1; + private static final String TELEMETRY_ENDPOINT = "https://client-telemetry.us-east-1.amazonaws.com"; + private static final String TELEMETRY_IDENTITY_POOL = "us-east-1:820fd6d1-95c0-4ca4-bffb-3f01d32da842"; + + // prevent instantiation + private TelemetryService() { } + + public static ToolkitTelemetryClient getClient() { + return CLIENT; + } + + private static ClientOverrideConfiguration.Builder nullDefaultProfileFile(final ClientOverrideConfiguration.Builder builder) { + return builder.defaultProfileFile(ProfileFile.builder() + .content(InputStream.nullInputStream()) + .type(ProfileFile.Type.CONFIGURATION) + .build()); + } + + private static ToolkitTelemetryClient createDefaultTelemetryClient() { + CognitoIdentityClient cognitoClient = CognitoIdentityClient.builder() + .credentialsProvider(AnonymousCredentialsProvider.create()) + .region(TELEMETRY_REGION) + .httpClient(ApacheHttpClient.create()) + .overrideConfiguration(builder -> nullDefaultProfileFile(builder)) + .build(); + AwsCredentialsProvider credentialsProvider = new AwsCognitoCredentialsProvider(TELEMETRY_IDENTITY_POOL, cognitoClient); + return ToolkitTelemetryClient.builder() + .credentialsProvider(credentialsProvider) + .endpointOverride(URI.create(TELEMETRY_ENDPOINT)) + .build(); + } +}