Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI: Bedrock support and misc improvements #849

Merged
merged 36 commits into from
Jul 27, 2024
Merged
Changes from 3 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2ee93a5
fix crash with one command-line argument
katrinafyi Jul 15, 2024
ec1a0f5
implement ping() on BedrockServer
katrinafyi Jul 15, 2024
60e3512
support Bedrock servers in CLI
katrinafyi Jul 15, 2024
a0e41a2
print server kind and tweak player sample printing
katrinafyi Jul 15, 2024
47ce944
JavaServer ping() doesn't work?
katrinafyi Jul 16, 2024
213fc2a
fix precommit warnings
katrinafyi Jul 17, 2024
848fc57
review: remove Bedrock ping()
katrinafyi Jul 17, 2024
f9577b5
review: change CLI ping comment to be more permanent
katrinafyi Jul 17, 2024
3a0ee8c
review: formalise hostip/hostport within QueryResponse
katrinafyi Jul 17, 2024
73a4543
review: only squash traceback in common errors
katrinafyi Jul 17, 2024
47f62fc
review: leading line break for multi-line motd
katrinafyi Jul 19, 2024
1130b99
Revert "review: formalise hostip/hostport within QueryResponse"
katrinafyi Jul 19, 2024
bb51ac5
review: use motd.to_minecraft() in json
katrinafyi Jul 19, 2024
b6a28fa
review amendment: factor out motd line breaking
katrinafyi Jul 19, 2024
de8be4d
review: refactor CLI json() to use dataclasses.asdict()
katrinafyi Jul 20, 2024
faf208b
amendment: add NoNameservers and remove ValueError from squashed errors
katrinafyi Jul 19, 2024
890d378
review: fallback logic in CLI ping
katrinafyi Jul 20, 2024
80079b3
review: use ip/port fields in CLI's JSON output
katrinafyi Jul 20, 2024
05d37a5
review: avoid kind() classmethod
katrinafyi Jul 20, 2024
6155980
review: clarify MOTD serialisation comment
katrinafyi Jul 20, 2024
b42b1b7
review: simplify ping fallback logic
katrinafyi Jul 20, 2024
6ae1dbf
make version consistent between status and query
katrinafyi Jul 21, 2024
ceb43ff
review: apply simplify() to motd in CLI JSON output
katrinafyi Jul 21, 2024
1799c3d
review: use separate JSON field for simplified MOTD
katrinafyi Jul 22, 2024
50b825e
review: remove MOTD fixup comment
katrinafyi Jul 22, 2024
c23d40d
review: update README with new CLI
katrinafyi Jul 22, 2024
4ad7f6c
review: no raw motd
katrinafyi Jul 23, 2024
8d29673
no --help output in readme
katrinafyi Jul 24, 2024
06e8b80
review: allow main() with no arguments
katrinafyi Jul 25, 2024
f82ae9e
Update mcstatus/__main__.py
katrinafyi Jul 25, 2024
80fb48b
avoid json collision
katrinafyi Jul 25, 2024
f4fdabd
oops! good linter
katrinafyi Jul 25, 2024
2540089
drike review
katrinafyi Jul 25, 2024
551caa4
good linter
katrinafyi Jul 25, 2024
9189de7
one more ci failure and i turn on the computer
katrinafyi Jul 25, 2024
d690735
also squash ConnectionError
katrinafyi Jul 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 61 additions & 32 deletions mcstatus/__main__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from __future__ import annotations
PerchunPak marked this conversation as resolved.
Show resolved Hide resolved

import dns.resolver
import sys
import json as _json
kevinkjt2000 marked this conversation as resolved.
Show resolved Hide resolved
import argparse
import socket
import warnings
import dataclasses
from typing import TYPE_CHECKING
from json import dumps as json_dumps

from mcstatus import JavaServer, BedrockServer
from mcstatus.responses import JavaStatusResponse
Expand All @@ -22,10 +25,33 @@ def _motd(motd: Motd) -> str:


def ping(server: SupportedServers) -> int:
# this method supports both Java and Bedrock.
# only Java supports the `ping` packet, and even then not always:
# https://github.com/py-mine/mcstatus/issues/850
print(f"{server.status().latency}")
notsup = "notsup"
PerchunPak marked this conversation as resolved.
Show resolved Hide resolved

# handle java and bedrock differences, as well as non-conformant servers
# which require a 'status' packet.

try:
ping_res = server.ping() if isinstance(server, JavaServer) else notsup
except Exception as e:
ping_res = e

# at this point, ping_res is NOTSUP for Bedrock, otherwise it is either a float or an Exception.

if isinstance(ping_res, (float, int)):
latency = ping_res
else:
latency = server.status().latency

if ping_res != notsup:
addr = f"{server.address.host}:{server.address.port}"
warnings.warn(
f"contacting {addr} failed with a 'ping' packet but succeeded with a 'status' packet,\n "
f"this is likely a bug in the server-side implementation.\n "
f"for more details, see: https://mcstatus.readthedocs.io/en/stable/pages/faq/\n",
stacklevel=1,
)

print(f"{latency}")
return 0


Expand All @@ -52,35 +78,38 @@ def status(server: SupportedServers) -> int:


def json(server: SupportedServers) -> int:
data = {}
data["online"] = False
data["kind"] = server.kind()
# Build data with responses and quit on exception
data = {"online": False, "kind": server.kind()}

status_res = query_res = None
try:
status_res = server.status(tries=1)
java_res = status_res if isinstance(status_res, JavaStatusResponse) else None
data["version"] = status_res.version.name
data["protocol"] = status_res.version.protocol
data["motd"] = status_res.motd.to_minecraft()
data["player_count"] = status_res.players.online
data["player_max"] = status_res.players.max
data["players"] = []
if java_res and java_res.players.sample is not None:
data["players"] = [{"name": player.name, "id": player.id} for player in java_res.players.sample]

data["ping"] = status_res.latency
data["online"] = True

if isinstance(server, JavaServer):
query_res = server.query(tries=1)
data["host_ip"] = query_res.raw["hostip"]
data["host_port"] = query_res.raw["hostport"]
data["map"] = query_res.map
data["plugins"] = query_res.software.plugins
except Exception: # TODO: Check what this actually excepts
pass

print(json_dumps(data))
except Exception as e:
if status_res is None:
data["error"] = str(e)

# construct 'data' dict outside try/except to ensure data processing errors
# are noticed.
data["online"] = bool(status_res or query_res)
ItsDrike marked this conversation as resolved.
Show resolved Hide resolved
if status_res is not None:
data["status"] = dataclasses.asdict(status_res)

# XXX: hack to fixup MOTD serialisation. should be implemented elsewhere.
PerchunPak marked this conversation as resolved.
Show resolved Hide resolved
assert "motd" in data["status"]
ItsDrike marked this conversation as resolved.
Show resolved Hide resolved
data["status"]["motd"] = {"raw": status_res.motd.to_minecraft()}
PerchunPak marked this conversation as resolved.
Show resolved Hide resolved

if query_res is not None:
# TODO: QueryResponse is not (yet?) a dataclass
data["query"] = qdata = {}

qdata["host_ip"] = query_res.raw["hostip"]
qdata["host_port"] = query_res.raw["hostport"]
katrinafyi marked this conversation as resolved.
Show resolved Hide resolved
qdata["map"] = query_res.map
qdata["plugins"] = query_res.software.plugins
qdata["raw"] = query_res.raw

_json.dump(data, sys.stdout)
return 0


Expand Down Expand Up @@ -139,11 +168,11 @@ def main(argv: list[str]) -> int:

args = parser.parse_args(argv)
lookup = JavaServer.lookup if not args.bedrock else BedrockServer.lookup
server = lookup(args.address)

try:
server = lookup(args.address)
return args.func(server)
except (socket.timeout, socket.gaierror, ValueError) as e:
except (socket.timeout, socket.gaierror, dns.resolver.NoNameservers) as e:
# catch and hide traceback for expected user-facing errors
print(f"Error: {e}", file=sys.stderr)
return 1
Expand Down
Loading