Skip to content

Commit

Permalink
refactor: move classes around
Browse files Browse the repository at this point in the history
  • Loading branch information
wu-vincent committed Sep 8, 2024
1 parent bcec0a4 commit 59aff7d
Show file tree
Hide file tree
Showing 12 changed files with 164 additions and 114 deletions.
8 changes: 5 additions & 3 deletions src/endstone_bstats/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from endstone_bstats._charts import ChartDataError, CustomChart
from endstone_bstats._charts.pie import SimplePie, AdvancedPie
from endstone_bstats._metrics import Metrics
from endstone_bstats._charts.advanced_pie import AdvancedPie
from endstone_bstats._charts.custom_chart import CustomChart
from endstone_bstats._charts.simple_pie import SimplePie
from endstone_bstats._config import MetricsConfig
from endstone_bstats._errors import ChartDataError
from endstone_bstats._metrics import Metrics

__all__ = [
"Metrics",
Expand Down
69 changes: 0 additions & 69 deletions src/endstone_bstats/_charts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,69 +0,0 @@
from __future__ import annotations

from abc import ABC, abstractmethod


class ChartDataError(Exception):
"""
Custom exception for errors when getting chart data.
"""

pass


class CustomChart(ABC):
"""
Represents a custom chart.
"""

def __init__(self, chart_id: str) -> None:
"""
Class constructor.
Args:
chart_id (str): The id of the chart.
Raises:
ValueError: If chart_id is None or empty.
"""
if not chart_id:
raise ValueError("chart_id cannot be None or empty!")

self.chart_id = chart_id

def _get_request_json_object(self) -> dict | None:
"""
Gets the JSON object for the chart request.
Returns:
dict: A dictionary representing the chart, or None if the data is invalid or an exception occurs.
Raises:
ChartDataError: If there is an error getting the chart data.
"""
chart = {"chartId": self.chart_id}
try:
data = self.get_chart_data()
if not data: # If the data is empty we don't send the chart.
return None

chart["data"] = data

except Exception as e:
raise ChartDataError(
f"Failed to get data for custom chart with id {self.chart_id}"
) from e

return chart

@abstractmethod
def get_chart_data(self) -> dict | None:
"""
Gets the data for the chart.
Returns:
dict: A dictionary with the chart data.
Raises:
Exception: If there is an error getting the chart data.
"""
Original file line number Diff line number Diff line change
@@ -1,37 +1,8 @@
from __future__ import annotations

from endstone_bstats._charts import CustomChart
from typing import Callable


class SimplePie(CustomChart):
def __init__(self, chart_id: str, get_value: Callable[[], str | None]) -> None:
"""
Class constructor.
Args:
chart_id (str): The id of the chart.
get_value (Callable[[], str | None]): The callable which is used to request the chart data.
"""

super().__init__(chart_id)
self.get_value = get_value

def get_chart_data(self) -> dict | None:
"""
Gets the data for the simple pie chart.
Returns:
dict | None: A dictionary with the chart data.
"""

data = {}
value = self.get_value()
if not value:
return None # skip the chart

data["value"] = value
return data
from endstone_bstats._charts.custom_chart import CustomChart


class AdvancedPie(CustomChart):
Expand Down
63 changes: 63 additions & 0 deletions src/endstone_bstats/_charts/custom_chart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from __future__ import annotations

from abc import ABC, abstractmethod

from endstone_bstats._errors import ChartDataError


class CustomChart(ABC):
"""
Represents a custom chart.
"""

def __init__(self, chart_id: str) -> None:
"""
Class constructor.
Args:
chart_id (str): The id of the chart.
Raises:
ValueError: If chart_id is None or empty.
"""
if not chart_id:
raise ValueError("chart_id cannot be None or empty!")

self.chart_id = chart_id

def _get_request_json_object(self) -> dict | None:
"""
Gets the JSON object for the chart request.
Returns:
dict: A dictionary representing the chart, or None if the data is invalid or an exception occurs.
Raises:
ChartDataError: If there is an error getting the chart data.
"""
chart = {"chartId": self.chart_id}
try:
data = self.get_chart_data()
if not data: # If the data is empty we don't send the chart.
return None

chart["data"] = data

except Exception as e:
raise ChartDataError(
f"Failed to get data for custom chart with id {self.chart_id}"
) from e

return chart

@abstractmethod
def get_chart_data(self) -> dict | None:
"""
Gets the data for the chart.
Returns:
dict: A dictionary with the chart data.
Raises:
Exception: If there is an error getting the chart data.
"""
35 changes: 35 additions & 0 deletions src/endstone_bstats/_charts/simple_pie.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from __future__ import annotations

from typing import Callable

from endstone_bstats._charts.custom_chart import CustomChart


class SimplePie(CustomChart):
def __init__(self, chart_id: str, get_value: Callable[[], str | None]) -> None:
"""
Class constructor.
Args:
chart_id (str): The id of the chart.
get_value (Callable[[], str | None]): The callable which is used to request the chart data.
"""

super().__init__(chart_id)
self.get_value = get_value

def get_chart_data(self) -> dict | None:
"""
Gets the data for the simple pie chart.
Returns:
dict | None: A dictionary with the chart data.
"""

data = {}
value = self.get_value()
if not value:
return None # skip the chart

data["value"] = value
return data
3 changes: 2 additions & 1 deletion src/endstone_bstats/_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path
import uuid
from pathlib import Path

import tomlkit


Expand Down
6 changes: 6 additions & 0 deletions src/endstone_bstats/_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class ChartDataError(Exception):
"""
Custom exception for errors when getting chart data.
"""

pass
48 changes: 41 additions & 7 deletions src/endstone_bstats/_metrics.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
from __future__ import annotations

import gzip
import io
import multiprocessing as mp
import os
import platform
import sys
import uuid
import gzip
import io
from pathlib import Path

import tomlkit
from endstone.plugin import Plugin
from pathlib import Path

from endstone_bstats import CustomChart

Expand Down Expand Up @@ -39,6 +41,9 @@ class Metrics:
_log_response_status_text: bool
_server_uuid: uuid.UUID

__instances: dict[Plugin, Metrics] = {}
__scheduler: mp.Process | None = None

def __init__(self, plugin: Plugin, plugin_id: int) -> None:
"""
Initializes the Metrics class with the provided plugin and plugin ID.
Expand All @@ -56,6 +61,11 @@ def __init__(self, plugin: Plugin, plugin_id: int) -> None:

self._load_config()

if self.enabled:
Metrics.__instances[self._plugin] = self
if not Metrics.__scheduler:
self._start_submitting()

@property
def enabled(self) -> bool:
"""
Expand All @@ -75,17 +85,39 @@ def add_chart(self, chart: CustomChart) -> None:
"""
self._charts.append(chart)

@property
def plugin_data(self) -> dict:
"""
Gets the plugin specific data.
Returns:
dict: The plugin specific data.
"""

custom_charts = []
for chart in self._charts:
chart_data = chart.get_chart_data()
if chart_data is not None:
custom_charts.append(chart_data)

return {
"pluginName": self._plugin.description.name,
"id": self._plugin_id,
"pluginVersion": self._plugin.description.version,
"customCharts": custom_charts,
}

@property
def _server_data(self) -> dict:
"""
Gets the server-specific data.
Gets the server specific data.
Returns:
dict: The server-specific data.
dict: The server specific data.
"""

server = self._plugin.server
data = {
return {
"serverUUID": str(self._server_uuid),
"playerAmount": len(server.online_players),
# TODO: online mode
Expand All @@ -97,7 +129,9 @@ def _server_data(self) -> dict:
"osVersion": platform.release(),
"coreCount": os.cpu_count(),
}
return data

def _start_submitting(self) -> None:
raise NotImplementedError()

def _load_config(self) -> None:
# Get the config file
Expand Down
1 change: 1 addition & 0 deletions tests/test_advanced_pie.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest

from endstone_bstats import AdvancedPie


Expand Down
3 changes: 2 additions & 1 deletion tests/test_custom_chart.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from endstone_bstats import CustomChart, ChartDataError

from endstone_bstats import ChartDataError, CustomChart


class TestCustomChart(CustomChart):
Expand Down
10 changes: 7 additions & 3 deletions tests/test_metrics_config.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import pytest
from pathlib import Path
import uuid
from pathlib import Path

import pytest
import tomlkit
from endstone_bstats import MetricsConfig # Make sure to import the class from the appropriate module

from endstone_bstats import (
MetricsConfig,
) # Make sure to import the class from the appropriate module


@pytest.fixture
Expand Down
1 change: 1 addition & 0 deletions tests/test_simple_pie.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest

from endstone_bstats import SimplePie


Expand Down

0 comments on commit 59aff7d

Please sign in to comment.