Skip to content

Commit

Permalink
Servers: split error-reporting server from the lobby (#11563)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanVanAtta committed Apr 2, 2023
1 parent d4088a9 commit f6da012
Show file tree
Hide file tree
Showing 47 changed files with 690 additions and 59 deletions.
10 changes: 10 additions & 0 deletions http-clients/error-reporting-client/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
dependencies {
implementation "io.github.openfeign:feign-core:$feignCoreVersion"
implementation "io.github.openfeign:feign-gson:$feignGsonVersion"
implementation project(":http-clients:feign-common")
implementation project(":http-clients:http-client-lib")
implementation project(":lib:java-extras")
testImplementation "ru.lanwen.wiremock:wiremock-junit5:$wireMockJunit5Version"
testImplementation "com.github.tomakehurst:wiremock:$wireMockVersion"
testImplementation project(":lib:test-common")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.triplea.http.client.error.report;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

@ToString
@Builder
@Getter
@EqualsAndHashCode
public class CanUploadErrorReportResponse {
/**
* True means a user can upload an error report. False means an error report is already uploaded.
* If true, then responseDetails and existingBugReportUrl will be null.
*/
@Nonnull private final Boolean canUpload;
/**
* Contains any message details that should be displayed to the user. EG: "This error is already
* uploaded"
*/
@Nullable private final String responseDetails;
/** Contains a link to any existing error report that matches the same error the user sees. */
@Nullable private final String existingBugReportUrl;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.triplea.http.client.error.report;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;

@ToString
@EqualsAndHashCode
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class CanUploadRequest {
private String gameVersion;
private String errorTitle;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.triplea.http.client.error.report;

import feign.FeignException;
import feign.RequestLine;
import java.net.URI;
import org.triplea.http.client.HttpClient;
import org.triplea.http.client.lib.HttpClientHeaders;

/** Http client to upload error reports to the http lobby server. */
public interface ErrorReportClient {
String ERROR_REPORT_PATH = "/error-report";
String CAN_UPLOAD_ERROR_REPORT_PATH = "/error-report-check";
int MAX_REPORTS_PER_DAY = 5;

/** Creates an error report uploader clients, sends error reports and gets a response back. */
static ErrorReportClient newClient(URI uri, String clientVersion) {
return HttpClient.newClient(
ErrorReportClient.class,
uri,
HttpClientHeaders.defaultHeadersWithClientVersion(clientVersion));
}

/**
* API to upload an exception error report from a TripleA client to TripleA server.
*
* @throws FeignException Thrown on non-2xx responses.
*/
@RequestLine("POST " + ErrorReportClient.ERROR_REPORT_PATH)
ErrorReportResponse uploadErrorReport(ErrorReportRequest request);

/**
* Checks if user can upload a request. A request can be uploaded if: - it has not yet been
* reported - reporting version is greater than fix version - user is not banned
*/
@RequestLine("POST " + ErrorReportClient.CAN_UPLOAD_ERROR_REPORT_PATH)
CanUploadErrorReportResponse canUploadErrorReport(CanUploadRequest canUploadRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.triplea.http.client.error.report;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.triplea.http.client.HttpClientConstants;
import org.triplea.java.StringUtils;

/** Represents data that would be uploaded to a server. */
@ToString
@EqualsAndHashCode
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
public class ErrorReportRequest {
/**
* GAME_VERSION_MAJOR_MINOR regex matches first digits, and optional;u a dot followed by more
* digits. Examples:<br>
* 1.1 -> 1.1<br>
* 2.3.1 -> 2.3<br>
* 10 -> 10<br>
* 2.3+1 -> 3.2<br>
* Of note, we have a variety of matches to account for old version formats and to handle possible
* future variety of versions.
*/
private static final Pattern GAME_VERSION_MAJOR_MINOR = Pattern.compile("^[0-9]+(\\.[0-9]+)?");

@Nonnull private String title;
@Nonnull private String body;
@Nonnull @Getter private String gameVersion;

public String getTitle() {
return StringUtils.truncate(title, HttpClientConstants.TITLE_MAX_LENGTH);
}

public String getBody() {
return StringUtils.truncate(body, HttpClientConstants.REPORT_BODY_MAX_LENGTH);
}

/**
* Returns the 'major.minor' part of the game version, eg: "2.6+123" -> "2.6". If the gameVersion
* value is in an unexpected format, we return the gameVersion value as-is.
*/
public String getSimpleGameVersion() {
Matcher m = GAME_VERSION_MAJOR_MINOR.matcher(gameVersion);
// return the matched part if found, otherwise just return 'gameVersion' as-is
return m.find() ? m.group() : gameVersion;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.triplea.http.client.error.report;

import javax.annotation.Nonnull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;

/** Data object that corresponds to the JSON response from lobby-server for error report. */
@ToString
@Builder
@Getter
@EqualsAndHashCode
@AllArgsConstructor
public class ErrorReportResponse {
/**
* A link to the github issue created (empty if there were problems creating the link). Server
* should return a 500 in case there are any problems creating the error report.
*/
@Nonnull private final String githubIssueLink;
}
3 changes: 3 additions & 0 deletions http-clients/http-client-lib/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies {
implementation project(":game-app:domain-data")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.triplea.http.client.lib;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import lombok.Builder;
import org.triplea.domain.data.SystemIdLoader;

/** Small class to encapsulate api key and create http Authorization header. */
@Builder
public class HttpClientHeaders {
public static final String VERSION_HEADER = "Triplea-Version";
public static final String SYSTEM_ID_HEADER = "System-Id";

@Nonnull private final String clientVersion;
private final String apiKey;
private static final String systemId = SystemIdLoader.load().getValue();

public static Map<String, String> defaultHeadersWithClientVersion(String clientVersion) {
return builder().clientVersion(clientVersion).build().createHeaders();
}

/** Creates headers containing 'System-Id' only. */
public Map<String, String> createHeaders() {
final Map<String, String> headerMap = new HashMap<>();
headerMap.put(VERSION_HEADER, clientVersion);
headerMap.put(SYSTEM_ID_HEADER, systemId);
if (apiKey != null) {
headerMap.put("Authorization", "Bearer " + apiKey);
}
return headerMap;
}
}
2 changes: 0 additions & 2 deletions servers/README-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,3 @@ the code a bit to be yet more modular.
Further, with very specific sub-folders and more executables, we will have more opportunity
to do continuous deployments on any update without having to worry for example about
disconnecting everyone from chat.


1 change: 0 additions & 1 deletion servers/error-reporting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ and the web-api for Github Issues.

The service provides throttling, it keeps tracks of error reports that have been submitted
and will allow only so many for a given window of time from a given user.

64 changes: 64 additions & 0 deletions servers/error-reporting/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
plugins {
id 'application'
id 'com.github.johnrengelman.shadow' version '7.1.2'
}

archivesBaseName = "$group-$name"
mainClassName = 'org.triplea.server.error.reporting.ErrorReportingServer'
ext {
releasesDir = file("$buildDir/releases")
}

jar {
manifest {
attributes 'Main-Class': mainClassName
}
}

task portableInstaller(type: Zip, group: 'release', dependsOn: shadowJar) {
from file('configuration.yml')

from(shadowJar.outputs) {
into 'bin'
}
}

task release(group: 'release', dependsOn: portableInstaller) {
doLast {
publishArtifacts(portableInstaller.outputs.files)
}
}

shadowJar {
archiveClassifier.set ''
// mergeServiceFiles is needed by dropwizard
// Without this configuration parsing breaks and is unable to find connector type 'http' for
// the following YAML snippet: server: {applicationConnectors: [{type: http, port: 8080}]
mergeServiceFiles()
}

configurations {
testImplementation {
// database-rider brings in slf4j-simple as a transitive dependency
// DropWizard has logback baked in and cannot have multiple slf4j bindings.
exclude group: 'org.slf4j', module: 'slf4j-simple'
}
}


dependencies {
implementation "io.dropwizard:dropwizard-core:$dropwizardVersion"
implementation "io.dropwizard:dropwizard-jdbi3:$dropwizardVersion"
implementation project(':http-clients:error-reporting-client')
implementation project(':http-clients:github-client')
implementation project(':http-clients:http-client-lib')
implementation project(':servers:server-lib')

runtimeOnly "org.postgresql:postgresql:$postgresqlVersion"

testImplementation "com.github.database-rider:rider-junit5:$databaseRiderVersion"
testImplementation "io.dropwizard:dropwizard-testing:$dropwizardVersion"
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
testImplementation project(':servers:server-test-support')
testImplementation project(':spitfire-server:database-test-support')
}
60 changes: 60 additions & 0 deletions servers/error-reporting/configuration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
githubApiToken: ${GITHUB_API_TOKEN:-}
githubWebServiceUrl: https://api.github.com
githubGameOrg: triplea-game
githubGameRepo: triplea
githubMapsOrgName: triplea-maps

# When disabled, API calls to github to create error reports will not
# be made and instead a hardcoded value returned.
errorReportToGithubEnabled: ${ERROR_REPORT_TO_GITHUB_ENABLED:-false}



database:
driverClass: org.postgresql.Driver
user: ${DATABASE_USER:-error_report_user}
password: ${DATABASE_PASSWORD:-error_report}
url: jdbc:postgresql://${DB_URL:-localhost:5432/error_report}
properties:
charSet: UTF-8

# the maximum amount of time to wait on an empty pool before throwing an exception
maxWaitForConnection: 1s

# the SQL query to run when validating a connection's liveness
validationQuery: select 1

# the minimum number of connections to keep open
minSize: 8

# the maximum number of connections to keep open
maxSize: 32

# whether or not idle connections should be validated
checkConnectionWhileIdle: false

# the amount of time to sleep between runs of the idle connection validation, abandoned cleaner and idle pool resizing
evictionInterval: 10s

# the minimum amount of time an connection must sit idle in the pool before it is eligible for eviction
minIdleTime: 1 minute


logging:
# The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
level: INFO
loggers:
# Set this to DEBUG to troubleshoot HTTP 400 "Unable to process JSON" errors.
io.dropwizard.jersey.jackson.JsonProcessingExceptionMapper: INFO

server:
applicationConnectors:
- type: http
port: ${HTTP_PORT:-8090}
# useForwardedHeaders is important for when behind a reverse proxy (NGINX)
# Without this 'getRemoteAddr' will return the IP of the reverse proxy server.
# By default when building locally useForwardedPorts should be 'false', but
# for all other environments that do have a NGINX server, the value should be
# set to true.
useForwardedHeaders: ${USE_FORWARDED_HEADERS:-false}
adminConnectors: []

0 comments on commit f6da012

Please sign in to comment.