__init__.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import datetime
  2. import json
  3. import os
  4. import ssl
  5. import subprocess
  6. import sys
  7. import typing
  8. import urllib.parse
  9. import urllib.request
  10. # official api documentation:
  11. # https://github.com/ToontownRewritten/api-doc/blob/master/login.md
  12. # https://github.com/ToontownRewritten/api-doc/blob/master/invasions.md
  13. LOGIN_API_URL = "https://www.toontownrewritten.com/api/login?format=json"
  14. if sys.platform == "darwin":
  15. TOONTOWN_LIBRARY_PATH = os.path.join(
  16. os.path.expanduser("~"), "Library", "Application Support", "Toontown Rewritten",
  17. )
  18. TOONTOWN_ENGINE_DEFAULT_PATH = os.path.join(
  19. TOONTOWN_LIBRARY_PATH, "Toontown Rewritten",
  20. )
  21. else:
  22. TOONTOWN_LIBRARY_PATH = None
  23. TOONTOWN_ENGINE_DEFAULT_PATH = None
  24. def start_engine(engine_path, gameserver, playcookie, **kwargs) -> subprocess.Popen:
  25. env = {
  26. "TTR_GAMESERVER": gameserver,
  27. "TTR_PLAYCOOKIE": playcookie,
  28. }
  29. if sys.platform == "darwin":
  30. env["DYLD_LIBRARY_PATH"] = os.path.join(
  31. TOONTOWN_LIBRARY_PATH, "Libraries.bundle",
  32. )
  33. env["DYLD_FRAMEWORK_PATH"] = os.path.join(TOONTOWN_LIBRARY_PATH, "Frameworks",)
  34. elif sys.platform == "linux" and "XAUTHORITY" in os.environ:
  35. # Fix for TTREngine reporting:
  36. # > :display:x11display(error): Could not open display ":0.0".
  37. # > :ToonBase: Default graphics pipe is glxGraphicsPipe (OpenGL).
  38. # > :ToonBase(warning): Unable to open 'onscreen' window.
  39. # > Traceback (most recent call last):
  40. # > File "<compiled '__voltorbmain__'>", line 0, in <module>
  41. # > [...]
  42. # > File "<compiled 'direct.vlt8f63e471.ShowBase'>", line 0, in vltf05fd21b
  43. # > Exception: Could not open window.
  44. env["XAUTHORITY"] = os.environ["XAUTHORITY"]
  45. return subprocess.Popen(
  46. args=[engine_path], cwd=os.path.dirname(engine_path), env=env, **kwargs,
  47. )
  48. def api_request(url, params=None, validate_ssl_cert=True):
  49. resp = urllib.request.urlopen(
  50. url=url,
  51. data=urllib.parse.urlencode(params).encode("ascii") if params else None,
  52. context=None if validate_ssl_cert else ssl._create_unverified_context(),
  53. )
  54. return json.loads(resp.read().decode("ascii"))
  55. class _LoginSuccessful:
  56. def __init__(self, playcookie, gameserver):
  57. self.playcookie = playcookie
  58. self.gameserver = gameserver
  59. class _LoginDelayed:
  60. def __init__(self, queue_token):
  61. self.queue_token = queue_token
  62. def login(
  63. username=None, password=None, queue_token=None, validate_ssl_cert=True
  64. ) -> typing.Union[_LoginSuccessful, _LoginDelayed]:
  65. if username is not None and queue_token is None:
  66. assert password is not None
  67. req_params = {
  68. "username": username,
  69. "password": password,
  70. }
  71. elif username is None and queue_token is not None:
  72. req_params = {
  73. "queueToken": queue_token,
  74. }
  75. else:
  76. raise Exception("either specify username or queue token")
  77. resp_data = api_request(
  78. url=LOGIN_API_URL, params=req_params, validate_ssl_cert=validate_ssl_cert,
  79. )
  80. if resp_data["success"] == "true":
  81. return _LoginSuccessful(
  82. playcookie=resp_data["cookie"], gameserver=resp_data["gameserver"],
  83. )
  84. if resp_data["success"] == "delayed":
  85. return _LoginDelayed(queue_token=resp_data["queueToken"],)
  86. raise Exception(repr(resp_data))
  87. def launch(
  88. engine_path, username, password, validate_ssl_certs=True, cpu_limit_percent=None
  89. ) -> None:
  90. result = login(
  91. username=username, password=password, validate_ssl_cert=validate_ssl_certs,
  92. )
  93. if isinstance(result, _LoginDelayed):
  94. result = login(
  95. queue_token=result.queue_token, validate_ssl_cert=validate_ssl_certs,
  96. )
  97. if not isinstance(result, _LoginSuccessful):
  98. raise Exception("unexpected response: {!r}".format(result))
  99. process = start_engine(
  100. engine_path=engine_path,
  101. gameserver=result.gameserver,
  102. playcookie=result.playcookie,
  103. )
  104. if cpu_limit_percent is not None:
  105. subprocess.Popen(
  106. args=[
  107. "cpulimit",
  108. "--pid",
  109. str(process.pid),
  110. "--limit",
  111. str(cpu_limit_percent),
  112. # '--verbose',
  113. ]
  114. )
  115. process.wait()