rlstatsapi 0.1.2__tar.gz → 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/LICENSE +21 -21
  2. rlstatsapi-0.1.5/PKG-INFO +149 -0
  3. rlstatsapi-0.1.5/README.md +126 -0
  4. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/pyproject.toml +47 -30
  5. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/setup.cfg +4 -4
  6. rlstatsapi-0.1.5/src/rlstatsapi/__init__.py +99 -0
  7. rlstatsapi-0.1.5/src/rlstatsapi/__main__.py +142 -0
  8. rlstatsapi-0.1.5/src/rlstatsapi/client.py +845 -0
  9. rlstatsapi-0.1.5/src/rlstatsapi/config.py +243 -0
  10. rlstatsapi-0.1.5/src/rlstatsapi/models.py +61 -0
  11. rlstatsapi-0.1.5/src/rlstatsapi/py.typed +0 -0
  12. rlstatsapi-0.1.5/src/rlstatsapi/state.py +110 -0
  13. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/src/rlstatsapi/types.py +392 -373
  14. rlstatsapi-0.1.5/src/rlstatsapi.egg-info/PKG-INFO +149 -0
  15. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/src/rlstatsapi.egg-info/SOURCES.txt +8 -1
  16. rlstatsapi-0.1.5/src/rlstatsapi.egg-info/entry_points.txt +2 -0
  17. rlstatsapi-0.1.5/src/rlstatsapi.egg-info/requires.txt +4 -0
  18. rlstatsapi-0.1.5/tests/test_config.py +123 -0
  19. rlstatsapi-0.1.2/PKG-INFO +0 -112
  20. rlstatsapi-0.1.2/README.md +0 -93
  21. rlstatsapi-0.1.2/src/rlstatsapi/__init__.py +0 -25
  22. rlstatsapi-0.1.2/src/rlstatsapi/client.py +0 -184
  23. rlstatsapi-0.1.2/src/rlstatsapi/models.py +0 -13
  24. rlstatsapi-0.1.2/src/rlstatsapi.egg-info/PKG-INFO +0 -112
  25. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/src/rlstatsapi/events.py +0 -0
  26. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/src/rlstatsapi.egg-info/dependency_links.txt +0 -0
  27. {rlstatsapi-0.1.2 → rlstatsapi-0.1.5}/src/rlstatsapi.egg-info/top_level.txt +0 -0
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Manu
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Manu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,149 @@
1
+ Metadata-Version: 2.4
2
+ Name: rlstatsapi
3
+ Version: 0.1.5
4
+ Summary: Rocket League Stats API client
5
+ Author: Manuel Cabral
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/manucabral/RocketLeagueStatsAPI
8
+ Project-URL: Repository, https://github.com/manucabral/RocketLeagueStatsAPI
9
+ Project-URL: Bug Tracker, https://github.com/manucabral/RocketLeagueStatsAPI/issues
10
+ Keywords: rocket-league,stats,socket,asyncio
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Topic :: Games/Entertainment
15
+ Classifier: Topic :: Software Development :: Libraries
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
22
+ Dynamic: license-file
23
+
24
+ <img width="600" alt="rlstatsapi-logo" src="https://github.com/manucabral/RocketLeagueStatsAPI/blob/main/docs/assets/social-preview.png" />
25
+
26
+ # Rocket League Stats API
27
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![PyPI version](https://img.shields.io/pypi/v/rlstatsapi.svg)](https://pypi.org/project/rlstatsapi/) [![Pylint](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml/badge.svg)](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml)
28
+ ![Downloads](https://img.shields.io/pypi/dm/rlstatsapi)
29
+
30
+ `rlstatsapi` is a small Python client for reading live Rocket League Stats API events over a local TCP socket.
31
+
32
+ - Full docs: [manucabral.github.io/RocketLeagueStatsAPI](https://manucabral.github.io/RocketLeagueStatsAPI/)
33
+ - Release history: [CHANGELOG.md](CHANGELOG.md)
34
+
35
+ ## Install
36
+
37
+ From [PyPI](https://pypi.org/project/rlstatsapi/):
38
+
39
+ ```bash
40
+ pip install rlstatsapi
41
+ ```
42
+
43
+ From GitHub:
44
+
45
+ ```bash
46
+ pip install git+https://github.com/manucabral/RocketLeagueStatsAPI.git
47
+ ```
48
+
49
+ ## Rocket League setup
50
+
51
+ Automatic setup from Python:
52
+
53
+ ```python
54
+ from rlstatsapi import configure_stats_api
55
+
56
+ configure_stats_api(enabled=True, port=49123, packet_send_rate=30)
57
+ ```
58
+
59
+ Manual setup:
60
+
61
+ `Documents\My Games\Rocket League\TAGame\Config\TAStatsAPI.ini`
62
+
63
+ ```ini
64
+ [TAGame.MatchStatsExporter_TA]
65
+ Port=49123
66
+ PacketSendRate=30
67
+ ```
68
+
69
+ In both cases, restart Rocket League after changing the config file.
70
+
71
+ Config discovery is currently Windows-first and targets common user config locations.
72
+
73
+ ## Quick start
74
+
75
+ ```python
76
+ import asyncio
77
+ from rlstatsapi import StatsClient
78
+
79
+
80
+ async def main() -> None:
81
+ async with StatsClient() as client:
82
+ client.on_any(lambda msg: print(msg.event, msg.data))
83
+ await asyncio.Event().wait()
84
+
85
+
86
+ asyncio.run(main())
87
+ ```
88
+
89
+ ## Demos
90
+
91
+ ### All events
92
+
93
+ ![All events demo](docs/videos/allevents.gif)
94
+
95
+ ### UI
96
+
97
+ ![UI demo](docs/videos/ui.gif)
98
+
99
+ ## CLI
100
+
101
+ ```bash
102
+ rlstatsapi status
103
+ rlstatsapi enable --port 49123 --rate 30
104
+ rlstatsapi listen --event GoalScored
105
+ ```
106
+
107
+ You can also listen to multiple events:
108
+
109
+ ```bash
110
+ rlstatsapi listen --event GoalScored --event MatchEnded --event MatchCreated
111
+ ```
112
+
113
+ ## Typing
114
+
115
+ For the best editor experience, use `cast_event_data(...)` or `msg.as_type(...)`.
116
+
117
+ ```python
118
+ from rlstatsapi.models import EventMessage
119
+ from rlstatsapi.types import GoalScoredPayload, cast_event_data
120
+
121
+
122
+ def on_goal(msg: EventMessage) -> None:
123
+ data: GoalScoredPayload = cast_event_data("GoalScored", msg.data)
124
+ print(data.get("Scorer", {}).get("Name"))
125
+ ```
126
+
127
+ ## More
128
+
129
+ - Full docs: [manucabral.github.io/RocketLeagueStatsAPI](https://manucabral.github.io/RocketLeagueStatsAPI/)
130
+ - Examples: [examples/](examples)
131
+ - Release history: [CHANGELOG.md](CHANGELOG.md)
132
+
133
+ ## Notes
134
+
135
+ - In current Rocket League builds this endpoint behaves like a TCP JSON stream in practice.
136
+ - Some fields, such as `MatchGuid`, are only present in online/LAN contexts.
137
+
138
+ ## Disclaimer
139
+
140
+ This project is an independent, community-made library and is **not affiliated with, endorsed by, or sponsored by Psyonix or Epic Games**.
141
+
142
+ Rocket League and related trademarks are the property of their respective owners.
143
+ Use this library at your own risk and in compliance with Rocket League’s terms and policies.
144
+
145
+ ## Contributors
146
+
147
+ <a href="https://github.com/manucabral/RocketLeagueStatsAPI/graphs/contributors">
148
+ <img src="https://contrib.rocks/image?repo=manucabral/RocketLeagueStatsAPI" alt="Contributors" />
149
+ </a>
@@ -0,0 +1,126 @@
1
+ <img width="600" alt="rlstatsapi-logo" src="https://github.com/manucabral/RocketLeagueStatsAPI/blob/main/docs/assets/social-preview.png" />
2
+
3
+ # Rocket League Stats API
4
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![PyPI version](https://img.shields.io/pypi/v/rlstatsapi.svg)](https://pypi.org/project/rlstatsapi/) [![Pylint](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml/badge.svg)](https://github.com/manucabral/RocketLeagueStatsAPI/actions/workflows/pylint.yml)
5
+ ![Downloads](https://img.shields.io/pypi/dm/rlstatsapi)
6
+
7
+ `rlstatsapi` is a small Python client for reading live Rocket League Stats API events over a local TCP socket.
8
+
9
+ - Full docs: [manucabral.github.io/RocketLeagueStatsAPI](https://manucabral.github.io/RocketLeagueStatsAPI/)
10
+ - Release history: [CHANGELOG.md](CHANGELOG.md)
11
+
12
+ ## Install
13
+
14
+ From [PyPI](https://pypi.org/project/rlstatsapi/):
15
+
16
+ ```bash
17
+ pip install rlstatsapi
18
+ ```
19
+
20
+ From GitHub:
21
+
22
+ ```bash
23
+ pip install git+https://github.com/manucabral/RocketLeagueStatsAPI.git
24
+ ```
25
+
26
+ ## Rocket League setup
27
+
28
+ Automatic setup from Python:
29
+
30
+ ```python
31
+ from rlstatsapi import configure_stats_api
32
+
33
+ configure_stats_api(enabled=True, port=49123, packet_send_rate=30)
34
+ ```
35
+
36
+ Manual setup:
37
+
38
+ `Documents\My Games\Rocket League\TAGame\Config\TAStatsAPI.ini`
39
+
40
+ ```ini
41
+ [TAGame.MatchStatsExporter_TA]
42
+ Port=49123
43
+ PacketSendRate=30
44
+ ```
45
+
46
+ In both cases, restart Rocket League after changing the config file.
47
+
48
+ Config discovery is currently Windows-first and targets common user config locations.
49
+
50
+ ## Quick start
51
+
52
+ ```python
53
+ import asyncio
54
+ from rlstatsapi import StatsClient
55
+
56
+
57
+ async def main() -> None:
58
+ async with StatsClient() as client:
59
+ client.on_any(lambda msg: print(msg.event, msg.data))
60
+ await asyncio.Event().wait()
61
+
62
+
63
+ asyncio.run(main())
64
+ ```
65
+
66
+ ## Demos
67
+
68
+ ### All events
69
+
70
+ ![All events demo](docs/videos/allevents.gif)
71
+
72
+ ### UI
73
+
74
+ ![UI demo](docs/videos/ui.gif)
75
+
76
+ ## CLI
77
+
78
+ ```bash
79
+ rlstatsapi status
80
+ rlstatsapi enable --port 49123 --rate 30
81
+ rlstatsapi listen --event GoalScored
82
+ ```
83
+
84
+ You can also listen to multiple events:
85
+
86
+ ```bash
87
+ rlstatsapi listen --event GoalScored --event MatchEnded --event MatchCreated
88
+ ```
89
+
90
+ ## Typing
91
+
92
+ For the best editor experience, use `cast_event_data(...)` or `msg.as_type(...)`.
93
+
94
+ ```python
95
+ from rlstatsapi.models import EventMessage
96
+ from rlstatsapi.types import GoalScoredPayload, cast_event_data
97
+
98
+
99
+ def on_goal(msg: EventMessage) -> None:
100
+ data: GoalScoredPayload = cast_event_data("GoalScored", msg.data)
101
+ print(data.get("Scorer", {}).get("Name"))
102
+ ```
103
+
104
+ ## More
105
+
106
+ - Full docs: [manucabral.github.io/RocketLeagueStatsAPI](https://manucabral.github.io/RocketLeagueStatsAPI/)
107
+ - Examples: [examples/](examples)
108
+ - Release history: [CHANGELOG.md](CHANGELOG.md)
109
+
110
+ ## Notes
111
+
112
+ - In current Rocket League builds this endpoint behaves like a TCP JSON stream in practice.
113
+ - Some fields, such as `MatchGuid`, are only present in online/LAN contexts.
114
+
115
+ ## Disclaimer
116
+
117
+ This project is an independent, community-made library and is **not affiliated with, endorsed by, or sponsored by Psyonix or Epic Games**.
118
+
119
+ Rocket League and related trademarks are the property of their respective owners.
120
+ Use this library at your own risk and in compliance with Rocket League’s terms and policies.
121
+
122
+ ## Contributors
123
+
124
+ <a href="https://github.com/manucabral/RocketLeagueStatsAPI/graphs/contributors">
125
+ <img src="https://contrib.rocks/image?repo=manucabral/RocketLeagueStatsAPI" alt="Contributors" />
126
+ </a>
@@ -1,30 +1,47 @@
1
- [build-system]
2
- requires = ["setuptools>=69", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "rlstatsapi"
7
- version = "0.1.2"
8
- description = "Rocket League Stats API client"
9
- readme = "README.md"
10
- requires-python = ">=3.11"
11
- license = { text = "MIT" }
12
- authors = [{ name = "Manuel Cabral" }]
13
- keywords = ["rocket-league", "stats", "socket", "asyncio"]
14
- classifiers = [
15
- "Programming Language :: Python :: 3",
16
- "Programming Language :: Python :: 3 :: Only",
17
- "License :: OSI Approved :: MIT License",
18
- "Operating System :: OS Independent",
19
- "Topic :: Games/Entertainment",
20
- "Topic :: Software Development :: Libraries",
21
- ]
22
-
23
- [project.urls]
24
- Homepage = "https://github.com/manucabral/RocketLeagueStatsAPI"
25
-
26
- [tool.setuptools]
27
- package-dir = {"" = "src"}
28
-
29
- [tool.setuptools.packages.find]
30
- where = ["src"]
1
+ [build-system]
2
+ requires = ["setuptools>=69", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "rlstatsapi"
7
+ version = "0.1.5"
8
+ description = "Rocket League Stats API client"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ authors = [{ name = "Manuel Cabral" }]
13
+ keywords = ["rocket-league", "stats", "socket", "asyncio"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3 :: Only",
17
+ "Operating System :: OS Independent",
18
+ "Topic :: Games/Entertainment",
19
+ "Topic :: Software Development :: Libraries",
20
+ ]
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/manucabral/RocketLeagueStatsAPI"
24
+ Repository = "https://github.com/manucabral/RocketLeagueStatsAPI"
25
+ "Bug Tracker" = "https://github.com/manucabral/RocketLeagueStatsAPI/issues"
26
+
27
+ [project.scripts]
28
+ rlstatsapi = "rlstatsapi.__main__:main"
29
+
30
+ [project.optional-dependencies]
31
+ dev = ["pytest>=8", "pytest-asyncio>=0.23"]
32
+
33
+ [tool.pytest.ini_options]
34
+ asyncio_mode = "auto"
35
+ testpaths = ["tests"]
36
+ markers = [
37
+ "integration: requires a live Rocket League exporter to be running",
38
+ ]
39
+
40
+ [tool.setuptools]
41
+ package-dir = {"" = "src"}
42
+
43
+ [tool.setuptools.packages.find]
44
+ where = ["src"]
45
+
46
+ [tool.setuptools.package-data]
47
+ rlstatsapi = ["py.typed"]
@@ -1,4 +1,4 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,99 @@
1
+ """
2
+ Public package surface for rlstatsapi.
3
+
4
+ Re-exports the client, envelope model, known event constants, and typed payload
5
+ helpers so consumers can import from `rlstatsapi` directly.
6
+ """
7
+
8
+ from importlib.metadata import PackageNotFoundError
9
+ from importlib.metadata import version as _pkg_version
10
+
11
+ from .client import StatsClient
12
+ from .config import (
13
+ DEFAULT_PACKET_SEND_RATE,
14
+ DEFAULT_STATS_API_FILENAME,
15
+ DEFAULT_STATS_API_PORT,
16
+ StatsAPIConfigStatus,
17
+ candidate_stats_api_paths,
18
+ configure_stats_api,
19
+ find_stats_api_config,
20
+ get_stats_api_status,
21
+ set_stats_api_enabled,
22
+ set_stats_api_port,
23
+ )
24
+ from .events import KNOWN_EVENTS
25
+ from .models import ClientMetrics, EventMessage, MatchStateSnapshot
26
+ from .state import MatchStateTracker
27
+ from .types import (
28
+ BallHitPayload,
29
+ ClockUpdatedSecondsPayload,
30
+ CountdownBeginPayload,
31
+ CrossbarHitPayload,
32
+ EventName,
33
+ GoalReplayEndPayload,
34
+ GoalReplayStartPayload,
35
+ GoalReplayWillEndPayload,
36
+ GoalScoredPayload,
37
+ KnownEventMessage,
38
+ MatchCreatedPayload,
39
+ MatchDestroyedPayload,
40
+ MatchEndedPayload,
41
+ MatchInitializedPayload,
42
+ MatchPausedPayload,
43
+ MatchUnpausedPayload,
44
+ PodiumStartPayload,
45
+ ReplayCreatedPayload,
46
+ RoundStartedPayload,
47
+ StatfeedEventPayload,
48
+ TypedEventMessage,
49
+ UpdateStatePayload,
50
+ cast_event_data,
51
+ )
52
+
53
+ try:
54
+ __version__: str = _pkg_version("rlstatsapi")
55
+ except PackageNotFoundError:
56
+ __version__ = "unknown"
57
+
58
+ __all__ = [
59
+ "__version__",
60
+ "StatsClient",
61
+ "StatsAPIConfigStatus",
62
+ "EventMessage",
63
+ "ClientMetrics",
64
+ "MatchStateSnapshot",
65
+ "MatchStateTracker",
66
+ "KNOWN_EVENTS",
67
+ "DEFAULT_PACKET_SEND_RATE",
68
+ "DEFAULT_STATS_API_FILENAME",
69
+ "DEFAULT_STATS_API_PORT",
70
+ "candidate_stats_api_paths",
71
+ "find_stats_api_config",
72
+ "get_stats_api_status",
73
+ "set_stats_api_enabled",
74
+ "set_stats_api_port",
75
+ "configure_stats_api",
76
+ "EventName",
77
+ "TypedEventMessage",
78
+ "KnownEventMessage",
79
+ "UpdateStatePayload",
80
+ "BallHitPayload",
81
+ "ClockUpdatedSecondsPayload",
82
+ "CountdownBeginPayload",
83
+ "CrossbarHitPayload",
84
+ "GoalReplayEndPayload",
85
+ "GoalReplayStartPayload",
86
+ "GoalReplayWillEndPayload",
87
+ "GoalScoredPayload",
88
+ "MatchCreatedPayload",
89
+ "MatchInitializedPayload",
90
+ "MatchDestroyedPayload",
91
+ "MatchEndedPayload",
92
+ "MatchPausedPayload",
93
+ "MatchUnpausedPayload",
94
+ "PodiumStartPayload",
95
+ "ReplayCreatedPayload",
96
+ "RoundStartedPayload",
97
+ "StatfeedEventPayload",
98
+ "cast_event_data",
99
+ ]
@@ -0,0 +1,142 @@
1
+ """Command-line entrypoint for common rlstatsapi setup and debugging tasks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import asyncio
7
+ import json
8
+ from dataclasses import asdict
9
+ from pathlib import Path
10
+ from typing import Sequence
11
+
12
+ from .client import StatsClient
13
+ from .config import (
14
+ DEFAULT_PACKET_SEND_RATE,
15
+ DEFAULT_STATS_API_PORT,
16
+ configure_stats_api,
17
+ get_stats_api_status,
18
+ )
19
+
20
+
21
+ def main(argv: Sequence[str] | None = None) -> int:
22
+ """Parse CLI args and dispatch the requested command."""
23
+ parser = _build_parser()
24
+ args = parser.parse_args(argv)
25
+ return args.func(args)
26
+
27
+
28
+ def _build_parser() -> argparse.ArgumentParser:
29
+ parser = argparse.ArgumentParser(prog="rlstatsapi")
30
+ subparsers = parser.add_subparsers(dest="command", required=True)
31
+
32
+ status_parser = subparsers.add_parser(
33
+ "status",
34
+ help="Show the current TAStatsAPI.ini status.",
35
+ )
36
+ status_parser.add_argument(
37
+ "--path", type=Path, help="Explicit TAStatsAPI.ini path."
38
+ )
39
+ status_parser.set_defaults(func=_run_status)
40
+
41
+ enable_parser = subparsers.add_parser(
42
+ "enable",
43
+ help="Enable the Rocket League Stats API in TAStatsAPI.ini.",
44
+ )
45
+ enable_parser.add_argument(
46
+ "--path", type=Path, help="Explicit TAStatsAPI.ini path."
47
+ )
48
+ enable_parser.add_argument("--port", type=int, default=DEFAULT_STATS_API_PORT)
49
+ enable_parser.add_argument(
50
+ "--rate",
51
+ type=int,
52
+ default=DEFAULT_PACKET_SEND_RATE,
53
+ help="PacketSendRate to write when enabling the exporter.",
54
+ )
55
+ enable_parser.set_defaults(func=_run_enable)
56
+
57
+ disable_parser = subparsers.add_parser(
58
+ "disable",
59
+ help="Disable the Rocket League Stats API in TAStatsAPI.ini.",
60
+ )
61
+ disable_parser.add_argument(
62
+ "--path", type=Path, help="Explicit TAStatsAPI.ini path."
63
+ )
64
+ disable_parser.add_argument("--port", type=int, default=DEFAULT_STATS_API_PORT)
65
+ disable_parser.set_defaults(func=_run_disable)
66
+
67
+ listen_parser = subparsers.add_parser(
68
+ "listen",
69
+ help="Connect to the local exporter and print live events.",
70
+ )
71
+ listen_parser.add_argument("--host", default="127.0.0.1")
72
+ listen_parser.add_argument("--port", type=int, default=DEFAULT_STATS_API_PORT)
73
+ listen_parser.add_argument(
74
+ "--event",
75
+ action="append",
76
+ default=[],
77
+ help="Filter to one or more event names. Repeat the flag to add more.",
78
+ )
79
+ listen_parser.add_argument(
80
+ "--raw",
81
+ action="store_true",
82
+ help="Include the raw transport JSON when available.",
83
+ )
84
+ listen_parser.set_defaults(func=_run_listen)
85
+
86
+ return parser
87
+
88
+
89
+ def _run_status(args: argparse.Namespace) -> int:
90
+ status = get_stats_api_status(args.path)
91
+ print(json.dumps(asdict(status), indent=2))
92
+ return 0
93
+
94
+
95
+ def _run_enable(args: argparse.Namespace) -> int:
96
+ status = configure_stats_api(
97
+ enabled=True,
98
+ port=args.port,
99
+ packet_send_rate=args.rate,
100
+ path=args.path,
101
+ )
102
+ print(json.dumps(asdict(status), indent=2))
103
+ print("Restart Rocket League after changing the config file.")
104
+ return 0
105
+
106
+
107
+ def _run_disable(args: argparse.Namespace) -> int:
108
+ status = configure_stats_api(
109
+ enabled=False,
110
+ port=args.port,
111
+ packet_send_rate=DEFAULT_PACKET_SEND_RATE,
112
+ path=args.path,
113
+ )
114
+ print(json.dumps(asdict(status), indent=2))
115
+ print("Restart Rocket League after changing the config file.")
116
+ return 0
117
+
118
+
119
+ def _run_listen(args: argparse.Namespace) -> int:
120
+ return asyncio.run(_listen(args))
121
+
122
+
123
+ async def _listen(args: argparse.Namespace) -> int:
124
+ async with StatsClient(
125
+ host=args.host,
126
+ port=args.port,
127
+ include_raw=args.raw,
128
+ ) as client:
129
+ print("Listening for Rocket League events. Press Ctrl+C to stop.")
130
+ async for message in client.events(*args.event):
131
+ payload = {
132
+ "event": message.event,
133
+ "data": message.data,
134
+ }
135
+ if args.raw:
136
+ payload["raw"] = message.raw
137
+ print(json.dumps(payload, indent=2, ensure_ascii=False))
138
+ return 0
139
+
140
+
141
+ if __name__ == "__main__":
142
+ raise SystemExit(main())