11package dev .faststats .core ;
22
3- import com .github .luben .zstd .Zstd ;
4- import com .google .gson .FormattingStyle ;
53import com .google .gson .JsonObject ;
6- import com .google .gson .JsonParser ;
7- import com .google .gson .stream .JsonReader ;
8- import com .google .gson .stream .JsonWriter ;
94import dev .faststats .core .chart .Chart ;
105import org .jetbrains .annotations .Async ;
116import org .jetbrains .annotations .Contract ;
127import org .jetbrains .annotations .MustBeInvokedByOverriders ;
138import org .jetbrains .annotations .VisibleForTesting ;
149import org .jspecify .annotations .Nullable ;
1510
11+ import java .io .ByteArrayInputStream ;
1612import java .io .IOException ;
1713import java .io .OutputStreamWriter ;
1814import java .net .ConnectException ;
2824import java .time .Duration ;
2925import java .util .HashSet ;
3026import java .util .Optional ;
27+ import java .util .Properties ;
3128import java .util .Set ;
3229import java .util .UUID ;
3330import java .util .concurrent .Executors ;
3431import java .util .concurrent .ScheduledExecutorService ;
3532import java .util .concurrent .TimeUnit ;
33+ import java .util .zip .GZIPInputStream ;
3634
3735public abstract class SimpleMetrics implements Metrics {
3836 private final HttpClient httpClient = HttpClient .newBuilder ()
@@ -95,9 +93,10 @@ protected boolean isSubmitting() {
9593 }
9694
9795 protected void submitData () {
98- try {
99- var data = createData ().toString ();
100- var compressed = Zstd .compress (data .getBytes (StandardCharsets .UTF_8 ), 6 );
96+ var data = createData ().toString ();
97+ try (var bytes = new ByteArrayInputStream (data .getBytes (StandardCharsets .UTF_8 ));
98+ var input = new GZIPInputStream (bytes )) {
99+ var compressed = input .readAllBytes ();
101100 var request = HttpRequest .newBuilder ()
102101 .POST (HttpRequest .BodyPublishers .ofByteArray (compressed ))
103102 .header ("Content-Encoding" , "zstd" )
@@ -154,7 +153,7 @@ protected JsonObject createData() {
154153 error ("Failed to build chart data: " + chart .getId (), e );
155154 }
156155 });
157-
156+
158157 appendDefaultData (charts );
159158
160159 data .addProperty ("server_id" , config .serverId ().toString ());
@@ -235,9 +234,9 @@ protected static final class Config implements Metrics.Config {
235234 protected Config (Path file ) throws IOException {
236235 var json = readOrEmpty (file );
237236
238- this .serverId = json .map (object -> UUID .fromString (object .get ("serverId" ). getAsString ( ))).orElseGet (UUID ::randomUUID );
239- this .enabled = json .map (object -> object .get ("enabled" ). getAsBoolean () ).orElse (true );
240- this .debug = json .map (object -> object .get ("debug" ). getAsBoolean () ).orElse (false );
237+ this .serverId = json .map (object -> UUID .fromString (object .getProperty ("serverId" ))).orElseGet (UUID ::randomUUID );
238+ this .enabled = json .map (object -> object .getProperty ("enabled" )). map ( Boolean :: parseBoolean ).orElse (true );
239+ this .debug = json .map (object -> object .getProperty ("debug" )). map ( Boolean :: parseBoolean ).orElse (false );
241240
242241 if (json .isEmpty ()) create (file , serverId );
243242 }
@@ -264,7 +263,7 @@ public boolean debug() {
264263 return debug ;
265264 }
266265
267- private static Optional <JsonObject > readOrEmpty (Path file ) throws IOException {
266+ private static Optional <Properties > readOrEmpty (Path file ) throws IOException {
268267 if (Files .isRegularFile (file )) {
269268 return Optional .of (read (file ));
270269 } else {
@@ -275,19 +274,32 @@ private static Optional<JsonObject> readOrEmpty(Path file) throws IOException {
275274 private static void create (Path file , UUID serverId ) throws IOException {
276275 Files .createDirectories (file .getParent ());
277276 try (var out = Files .newOutputStream (file , StandardOpenOption .CREATE_NEW );
278- var writer = new JsonWriter (new OutputStreamWriter (out , StandardCharsets .UTF_8 ))) {
279- writer .setFormattingStyle (FormattingStyle .PRETTY );
280- writer .beginObject ();
281- writer .name ("serverId" ).value (serverId .toString ());
282- writer .name ("enabled" ).value (true );
283- writer .name ("debug" ).value (false );
284- writer .endObject ();
277+ var writer = new OutputStreamWriter (out , StandardCharsets .UTF_8 )) {
278+ var properties = new Properties ();
279+
280+ properties .setProperty ("serverId" , serverId .toString ());
281+ properties .setProperty ("enabled" , Boolean .toString (true ));
282+ properties .setProperty ("debug" , Boolean .toString (false ));
283+
284+ var comment = """
285+ FastStats (https://faststats.dev) collects some basic information for plugin authors, like
286+ # how many people use their plugin and their total player count. It's recommended to keep
287+ # metrics enabled, but if you're not comfortable with this, you can turn this setting off.
288+ # There is no performance penalty associated with having metrics enabled, and data sent to
289+ # FastStats is fully anonymous.
290+
291+ # If you suspect a plugin is collecting personal data or bypassing the "enabled" option,
292+ # please report it to the FastStats team (https://faststats.dev/abuse).
293+ """ ;
294+ properties .store (writer , comment );
285295 }
286296 }
287297
288- private static JsonObject read (Path file ) throws IOException {
289- try (var reader = new JsonReader (Files .newBufferedReader (file , StandardCharsets .UTF_8 ))) {
290- return JsonParser .parseReader (reader ).getAsJsonObject ();
298+ private static Properties read (Path file ) throws IOException {
299+ try (var reader = Files .newBufferedReader (file , StandardCharsets .UTF_8 )) {
300+ var properties = new Properties ();
301+ properties .load (reader );
302+ return properties ;
291303 }
292304 }
293305 }
0 commit comments