@@ -60,14 +60,14 @@ public abstract class SimpleMetrics implements Metrics {
6060
6161 @ Contract (mutates = "io" )
6262 @ SuppressWarnings ("PatternValidation" )
63- protected SimpleMetrics (Factory <?> factory , Path config ) throws IllegalStateException {
63+ protected SimpleMetrics (Factory <?> factory , Config config ) throws IllegalStateException {
6464 if (factory .token == null ) throw new IllegalStateException ("Token must be specified" );
6565
66- this .config = new Config ( config ) ;
67- this .charts = this . config .additionalMetrics ? Set .copyOf (factory .charts ) : Set .of ();
68- this .debug = factory .debug || Boolean .getBoolean ("faststats.debug" ) || this . config .debug ();
66+ this .config = config ;
67+ this .charts = config .additionalMetrics ? Set .copyOf (factory .charts ) : Set .of ();
68+ this .debug = factory .debug || Boolean .getBoolean ("faststats.debug" ) || config .debug ();
6969 this .token = factory .token ;
70- this .tracker = this . config .errorTracking ? factory .tracker : null ;
70+ this .tracker = config .errorTracking ? factory .tracker : null ;
7171 this .url = factory .url ;
7272
7373 Runtime .getRuntime ().addShutdownHook (new Thread (() -> {
@@ -80,6 +80,11 @@ protected SimpleMetrics(Factory<?> factory, Path config) throws IllegalStateExce
8080 }, "metrics-shutdown-thread " + getClass ().getName ()));
8181 }
8282
83+ @ Contract (mutates = "io" )
84+ protected SimpleMetrics (Factory <?> factory , Path config ) throws IllegalStateException {
85+ this (factory , Config .read (config ));
86+ }
87+
8388 @ VisibleForTesting
8489 protected SimpleMetrics (Config config , Set <Chart <?>> charts , @ Token String token , @ Nullable ErrorTracker tracker , URI url , boolean debug ) {
8590 if (!token .matches (Token .PATTERN )) {
@@ -339,21 +344,43 @@ public Metrics.Factory<T> url(URI url) {
339344 }
340345 }
341346
342- protected static final class Config implements Metrics .Config {
343- private final UUID serverId ;
344- private final boolean additionalMetrics ;
345- private final boolean debug ;
346- private final boolean enabled ;
347- private final boolean errorTracking ;
348- private final boolean firstRun ;
347+ public record Config (
348+ UUID serverId ,
349+ boolean additionalMetrics ,
350+ boolean debug ,
351+ boolean enabled ,
352+ boolean errorTracking ,
353+ boolean firstRun
354+ ) implements Metrics .Config {
355+
356+ public static final String DEFAULT_COMMENT = """
357+ FastStats (https://faststats.dev) collects anonymous usage statistics for plugin developers.
358+ # This helps developers understand how their projects are used in the real world.
359+ #
360+ # No IP addresses, player data, or personal information is collected.
361+ # The server ID below is randomly generated and can be regenerated at any time.
362+ #
363+ # Enabling metrics has no noticeable performance impact.
364+ # Keeping metrics enabled is recommended, but you can disable them by setting 'enabled=false'.
365+ #
366+ # If you suspect a plugin is collecting personal data or bypassing the "enabled" option,
367+ # please report it at: https://faststats.dev/abuse
368+ #
369+ # For more information, visit: https://faststats.dev/info
370+ """ ;
349371
350372 @ Contract (mutates = "io" )
351- protected Config (Path file ) {
373+ public static Config read (Path file ) throws RuntimeException {
374+ return read (file , DEFAULT_COMMENT , false , false );
375+ }
376+
377+ @ Contract (mutates = "io" )
378+ public static Config read (Path file , String comment , boolean externallyManaged , boolean externallyEnabled ) throws RuntimeException {
352379 var properties = readOrEmpty (file );
353- this . firstRun = properties .isEmpty ();
354- var saveConfig = new AtomicBoolean (this . firstRun );
380+ var firstRun = properties .isEmpty ();
381+ var saveConfig = new AtomicBoolean (firstRun );
355382
356- this . serverId = properties .map (object -> object .getProperty ("serverId" )).map (string -> {
383+ var serverId = properties .map (object -> object .getProperty ("serverId" )).map (string -> {
357384 try {
358385 var trimmed = string .trim ();
359386 var corrected = trimmed .length () > 36 ? trimmed .substring (0 , 36 ) : trimmed ;
@@ -375,54 +402,21 @@ protected Config(Path file) {
375402 });
376403 };
377404
378- this . enabled = predicate .test ("enabled" , true );
379- this . errorTracking = predicate .test ("submitErrors" , true );
380- this . additionalMetrics = predicate .test ("submitAdditionalMetrics" , true );
381- this . debug = predicate .test ("debug" , false );
405+ var enabled = externallyManaged ? externallyEnabled : predicate .test ("enabled" , true );
406+ var errorTracking = predicate .test ("submitErrors" , true );
407+ var additionalMetrics = predicate .test ("submitAdditionalMetrics" , true );
408+ var debug = predicate .test ("debug" , false );
382409
383410 if (saveConfig .get ()) try {
384- save (file , serverId , enabled , errorTracking , additionalMetrics , debug );
411+ save (file , externallyManaged , comment , serverId , enabled , errorTracking , additionalMetrics , debug );
385412 } catch (IOException e ) {
386413 throw new RuntimeException ("Failed to save metrics config" , e );
387414 }
388- }
389415
390- @ VisibleForTesting
391- public Config (UUID serverId , boolean enabled , boolean errorTracking , boolean additionalMetrics , boolean debug ) {
392- this .serverId = serverId ;
393- this .enabled = enabled ;
394- this .debug = debug ;
395- this .errorTracking = errorTracking ;
396- this .additionalMetrics = additionalMetrics ;
397- this .firstRun = false ;
398- }
399-
400- @ Override
401- public UUID serverId () {
402- return serverId ;
403- }
404-
405- @ Override
406- public boolean enabled () {
407- return enabled ;
408- }
409-
410- @ Override
411- public boolean errorTracking () {
412- return errorTracking ;
413- }
414-
415- @ Override
416- public boolean additionalMetrics () {
417- return additionalMetrics ;
418- }
419-
420- @ Override
421- public boolean debug () {
422- return debug ;
416+ return new Config (serverId , additionalMetrics , debug , enabled , errorTracking , firstRun );
423417 }
424418
425- private static Optional <Properties > readOrEmpty (Path file ) {
419+ private static Optional <Properties > readOrEmpty (Path file ) throws RuntimeException {
426420 if (!Files .isRegularFile (file )) return Optional .empty ();
427421 try (var reader = Files .newBufferedReader (file , UTF_8 )) {
428422 var properties = new Properties ();
@@ -433,33 +427,18 @@ private static Optional<Properties> readOrEmpty(Path file) {
433427 }
434428 }
435429
436- private static void save (Path file , UUID serverId , boolean enabled , boolean errorTracking , boolean additionalMetrics , boolean debug ) throws IOException {
430+ private static void save (Path file , boolean externallyManaged , String comment , UUID serverId , boolean enabled , boolean errorTracking , boolean additionalMetrics , boolean debug ) throws IOException {
437431 Files .createDirectories (file .getParent ());
438432 try (var out = Files .newOutputStream (file );
439433 var writer = new OutputStreamWriter (out , UTF_8 )) {
440434 var properties = new Properties ();
441435
442436 properties .setProperty ("serverId" , serverId .toString ());
443- properties .setProperty ("enabled" , Boolean .toString (enabled ));
437+ if (! externallyManaged ) properties .setProperty ("enabled" , Boolean .toString (enabled ));
444438 properties .setProperty ("submitErrors" , Boolean .toString (errorTracking ));
445439 properties .setProperty ("submitAdditionalMetrics" , Boolean .toString (additionalMetrics ));
446440 properties .setProperty ("debug" , Boolean .toString (debug ));
447441
448- var comment = """
449- FastStats (https://faststats.dev) collects anonymous usage statistics for plugin developers.
450- # This helps developers understand how their projects are used in the real world.
451- #
452- # No IP addresses, player data, or personal information is collected.
453- # The server ID below is randomly generated and can be regenerated at any time.
454- #
455- # Enabling metrics has no noticeable performance impact.
456- # Keeping metrics enabled is recommended, but you can disable them by setting 'enabled=false'.
457- #
458- # If you suspect a plugin is collecting personal data or bypassing the "enabled" option,
459- # please report it at: https://faststats.dev/abuse
460- #
461- # For more information, visit: https://faststats.dev/info
462- """ ;
463442 properties .store (writer , comment );
464443 }
465444 }
0 commit comments