rustplus 6.1.3__tar.gz → 6.2.1__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 (124) hide show
  1. {rustplus-6.1.3/rustplus.egg-info → rustplus-6.2.1}/PKG-INFO +2 -2
  2. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/__init__.py +1 -1
  3. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/commands/command_options.py +1 -1
  4. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/events/chat_event.py +2 -4
  5. rustplus-6.2.1/rustplus/identification/__init__.py +2 -0
  6. rustplus-6.2.1/rustplus/identification/server_details.py +85 -0
  7. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/camera/camera_manager.py +4 -4
  8. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/camera/camera_parser.py +2 -2
  9. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/ratelimiter/__init__.py +8 -10
  10. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/websocket/ws.py +36 -39
  11. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/rust_api.py +31 -33
  12. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_chat_message.py +1 -2
  13. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_item.py +1 -2
  14. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/grab_items.py +1 -3
  15. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/utils.py +5 -3
  16. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/yielding_event.py +2 -2
  17. {rustplus-6.1.3 → rustplus-6.2.1/rustplus.egg-info}/PKG-INFO +2 -2
  18. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus.egg-info/SOURCES.txt +0 -2
  19. {rustplus-6.1.3 → rustplus-6.2.1}/setup.py +1 -1
  20. rustplus-6.1.3/rustplus/identification/__init__.py +0 -2
  21. rustplus-6.1.3/rustplus/identification/server_details.py +0 -39
  22. rustplus-6.1.3/rustplus/remote/proxy/__init__.py +0 -1
  23. rustplus-6.1.3/rustplus/remote/proxy/proxy_value_grabber.py +0 -32
  24. {rustplus-6.1.3 → rustplus-6.2.1}/LICENSE +0 -0
  25. {rustplus-6.1.3 → rustplus-6.2.1}/MANIFEST.in +0 -0
  26. {rustplus-6.1.3 → rustplus-6.2.1}/README.md +0 -0
  27. {rustplus-6.1.3 → rustplus-6.2.1}/requirements.txt +0 -0
  28. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/annotations/__init__.py +0 -0
  29. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/annotations/chat_event.py +0 -0
  30. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/annotations/clan_event.py +0 -0
  31. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/annotations/command.py +0 -0
  32. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/annotations/entity_event.py +0 -0
  33. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/annotations/protobuf_event.py +0 -0
  34. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/annotations/team_event.py +0 -0
  35. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/commands/__init__.py +0 -0
  36. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/commands/chat_command.py +0 -0
  37. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/commands/chat_command_data.py +0 -0
  38. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/events/__init__.py +0 -0
  39. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/events/clan_info_event.py +0 -0
  40. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/events/entity_event.py +0 -0
  41. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/events/protobuf_event.py +0 -0
  42. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/events/team_event.py +0 -0
  43. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/exceptions/__init__.py +0 -0
  44. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/exceptions/exceptions.py +0 -0
  45. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Airfield.svg +0 -0
  46. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Apartments_Complex.svg +0 -0
  47. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Arctic_Research_Base.svg +0 -0
  48. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Bandit_Camp.svg +0 -0
  49. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Dome.svg +0 -0
  50. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Excavator.svg +0 -0
  51. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Ferry_Terminal.svg +0 -0
  52. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Fishing_Village.svg +0 -0
  53. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Gas_Station.svg +0 -0
  54. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/HQM_Quarry.svg +0 -0
  55. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Harbor.svg +0 -0
  56. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Jungle_Ziggurat.svg +0 -0
  57. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Junkyard.svg +0 -0
  58. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Launch_Site.svg +0 -0
  59. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Lighthouse.svg +0 -0
  60. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Military_Base.svg +0 -0
  61. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Military_Tunnels.svg +0 -0
  62. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Mining_Outpost.svg +0 -0
  63. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Missile_Silo.svg +0 -0
  64. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Oil_Rig_Large.svg +0 -0
  65. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Oil_Rig_Small.svg +0 -0
  66. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Outpost.svg +0 -0
  67. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Powerplant.svg +0 -0
  68. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Radtown.svg +0 -0
  69. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Satellite_Dish.svg +0 -0
  70. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Sewer_Branch.svg +0 -0
  71. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Stables.svg +0 -0
  72. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Stone_Quarry.svg +0 -0
  73. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Sulfur_Quarry.svg +0 -0
  74. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Supermarket.svg +0 -0
  75. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Swamp.svg +0 -0
  76. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Trainyard.svg +0 -0
  77. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Tunnel_Entrance.svg +0 -0
  78. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Underwater_Lab.svg +0 -0
  79. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/Water_Treatment.svg +0 -0
  80. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/__init__.py +0 -0
  81. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/cargo.png +0 -0
  82. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/chinook.png +0 -0
  83. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/chinook_blades.png +0 -0
  84. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/crate.png +0 -0
  85. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/explosion.png +0 -0
  86. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/icon.png +0 -0
  87. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/patrol.png +0 -0
  88. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/icons/vending_machine.png +0 -0
  89. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/identification/handler_list.py +0 -0
  90. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/identification/registered_listener.py +0 -0
  91. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/__init__.py +0 -0
  92. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/camera/__init__.py +0 -0
  93. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/camera/camera_constants.py +0 -0
  94. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/camera/structures.py +0 -0
  95. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/fcm/__init__.py +0 -0
  96. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/fcm/fcm_listener.py +0 -0
  97. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/nexus/__init__.py +0 -0
  98. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/nexus/nexus_interface.py +0 -0
  99. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/rustplus_proto/__init__.py +0 -0
  100. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/rustplus_proto/rustplus.py +0 -0
  101. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/remote/websocket/__init__.py +0 -0
  102. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/__init__.py +0 -0
  103. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/clans/__init__.py +0 -0
  104. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/clans/rust_clan_info.py +0 -0
  105. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/clans/rust_clan_message.py +0 -0
  106. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_contents.py +0 -0
  107. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_entity_info.py +0 -0
  108. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_error.py +0 -0
  109. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_info.py +0 -0
  110. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_map.py +0 -0
  111. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_marker.py +0 -0
  112. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_team_info.py +0 -0
  113. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/rust_time.py +0 -0
  114. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/serialization.py +0 -0
  115. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/structs/util.py +0 -0
  116. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/__init__.py +0 -0
  117. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/deprecated.py +0 -0
  118. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/emojis.py +0 -0
  119. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/fonts/PermanentMarker.ttf +0 -0
  120. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus/utils/fonts/__init__.py +0 -0
  121. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus.egg-info/dependency_links.txt +0 -0
  122. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus.egg-info/requires.txt +0 -0
  123. {rustplus-6.1.3 → rustplus-6.2.1}/rustplus.egg-info/top_level.txt +0 -0
  124. {rustplus-6.1.3 → rustplus-6.2.1}/setup.cfg +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rustplus
3
- Version: 6.1.3
3
+ Version: 6.2.1
4
4
  Summary: A python wrapper for the Rust Plus API
5
5
  Home-page: https://github.com/olijeffers0n/rustplus
6
6
  Author: olijeffers0n
7
7
  License: MIT
8
8
  Project-URL: Issue tracker, https://github.com/olijeffers0n/rustplus/issues
9
- Requires-Python: >=3.8.0
9
+ Requires-Python: >=3.10.0
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
12
  Requires-Dist: websockets
@@ -22,5 +22,5 @@ from .structs import RustError, RustMarker, Vector
22
22
 
23
23
  __name__ = "rustplus"
24
24
  __author__ = "olijeffers0n"
25
- __version__ = "6.1.3"
25
+ __version__ = "6.2.1"
26
26
  __support__ = "Discord: https://discord.gg/nQqJe8qvP8"
@@ -2,7 +2,7 @@ from ..exceptions import PrefixNotDefinedError
2
2
 
3
3
 
4
4
  class CommandOptions:
5
- def __init__(self, prefix: str = None) -> None:
5
+ def __init__(self, prefix: str) -> None:
6
6
  if prefix is None:
7
7
  raise PrefixNotDefinedError("No prefix")
8
8
 
@@ -1,14 +1,12 @@
1
1
  from rustplus.identification.handler_list import HandlerList
2
2
  from ..structs import RustChatMessage
3
3
 
4
- from typing import Union
5
-
6
4
 
7
5
  class ChatEventPayload:
8
6
  HANDLER_LIST = HandlerList()
9
7
 
10
8
  def __init__(
11
- self, message: RustChatMessage, is_clan: bool, clan_id: Union[int, None]
9
+ self, message: RustChatMessage, is_clan: bool, clan_id: int | None
12
10
  ) -> None:
13
11
  self._message = message
14
12
  self._is_clan = is_clan
@@ -23,5 +21,5 @@ class ChatEventPayload:
23
21
  return self._is_clan
24
22
 
25
23
  @property
26
- def clan_id(self) -> Union[int, None]:
24
+ def clan_id(self) -> int | None:
27
25
  return self._clan_id
@@ -0,0 +1,2 @@
1
+ from .registered_listener import RegisteredListener
2
+ from .server_details import ServerDetails, DirectEndpoint, RelayEndpoint
@@ -0,0 +1,85 @@
1
+ import base64
2
+ import time
3
+ from dataclasses import dataclass, field
4
+
5
+ from websockets.typing import Subprotocol
6
+
7
+
8
+ def _b64url(s: str) -> str:
9
+ return base64.urlsafe_b64encode(s.encode()).decode().rstrip("=")
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class DirectEndpoint:
14
+ ip: str
15
+ port: int | None = None
16
+ secure: bool = False
17
+
18
+ def id(self) -> str:
19
+ return f"{self.ip}:{self.port}" if self.port is not None else self.ip
20
+
21
+ def uri(self) -> str:
22
+ scheme = "wss" if self.secure else "ws"
23
+ host = self.ip if self.port is None else f"{self.ip}:{self.port}"
24
+ return f"{scheme}://{host}"
25
+
26
+ @staticmethod
27
+ def connect_kwargs() -> dict:
28
+ return {}
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class RelayEndpoint:
33
+ server_id: str
34
+ # secret and short-lived: excluded from repr, eq and hash
35
+ auth_token: str = field(repr=False, compare=False)
36
+ host: str = "companion-rust.facepunch.com"
37
+ version: int = int(time.time() * 1000)
38
+
39
+ def id(self) -> str:
40
+ return self.server_id
41
+
42
+ def uri(self) -> str:
43
+ return f"wss://{self.host}/socket/{self.server_id}?v={self.version}"
44
+
45
+ def connect_kwargs(self) -> dict:
46
+ return {
47
+ "subprotocols": [
48
+ Subprotocol("rustplus.auth.v1"),
49
+ Subprotocol(_b64url(self.auth_token)),
50
+ ],
51
+ "origin": "https://app.playrust.com",
52
+ }
53
+
54
+
55
+ Endpoint = DirectEndpoint | RelayEndpoint
56
+
57
+
58
+ @dataclass(frozen=True)
59
+ class ServerDetails:
60
+ endpoint: Endpoint
61
+ player_id: int
62
+ player_token: int = field(repr=False)
63
+
64
+ @classmethod
65
+ def direct(
66
+ cls,
67
+ ip: str,
68
+ port: int | None,
69
+ player_id: int,
70
+ player_token: int,
71
+ secure: bool = False,
72
+ ):
73
+ return cls(
74
+ DirectEndpoint(str(ip), int(port) if port else None, secure),
75
+ int(player_id),
76
+ int(player_token),
77
+ )
78
+
79
+ @classmethod
80
+ def facepunch(
81
+ cls, server_id: str, auth_token: str, player_id: int, player_token: int
82
+ ):
83
+ return cls(
84
+ RelayEndpoint(server_id, auth_token), int(player_id), int(player_token)
85
+ )
@@ -1,5 +1,5 @@
1
1
  import time
2
- from typing import Iterable, Union, List, Coroutine, Set, Callable
2
+ from typing import Iterable, List, Coroutine, Set, Callable
3
3
  from PIL import Image
4
4
 
5
5
  from .camera_parser import Parser
@@ -18,7 +18,7 @@ from .structures import CameraInfo, Entity, LimitedQueue
18
18
 
19
19
  class CameraManager:
20
20
 
21
- ACTIVE_INSTANCE: Union["CameraManager", None] = None
21
+ ACTIVE_INSTANCE: "CameraManager | None" = None
22
22
 
23
23
  def __init__(
24
24
  self, rust_socket, cam_id: str, cam_info_message: AppCameraInfo
@@ -60,7 +60,7 @@ class CameraManager:
60
60
  render_entities: bool = True,
61
61
  entity_render_distance: float | int = float("inf"),
62
62
  max_entity_amount: float | int = float("inf"),
63
- ) -> Union[Image.Image, None]:
63
+ ) -> Image.Image | None:
64
64
  if self._last_packets is None:
65
65
  return None
66
66
 
@@ -97,7 +97,7 @@ class CameraManager:
97
97
  render_entities: bool = True,
98
98
  entity_render_distance: float | int = float("inf"),
99
99
  max_entity_amount: float | int = float("inf"),
100
- ) -> Union[Image.Image, None]:
100
+ ) -> Image.Image | None:
101
101
  return await self._create_frame(
102
102
  render_entities, entity_render_distance, max_entity_amount
103
103
  )
@@ -2,7 +2,7 @@ import math
2
2
  from importlib import resources
3
3
  from math import radians, tan
4
4
  import random
5
- from typing import Union, Tuple, List, Any, Dict
5
+ from typing import Tuple, List, Any, Dict
6
6
  import numpy as np
7
7
  from scipy.spatial import ConvexHull
8
8
  from PIL import Image, ImageDraw, ImageFont
@@ -166,7 +166,7 @@ class Parser:
166
166
 
167
167
  return False
168
168
 
169
- def next_ray(self, ray_data) -> List[Union[float, int]]:
169
+ def next_ray(self, ray_data) -> List[float | int]:
170
170
  byte = ray_data[self.data_pointer]
171
171
  self.data_pointer += 1
172
172
 
@@ -64,8 +64,8 @@ class RateLimiter:
64
64
  self.socket_buckets[server_details] = TokenBucket(
65
65
  current, maximum, refresh_rate, refresh_amount
66
66
  )
67
- if server_details.get_server_string() not in self.server_buckets:
68
- self.server_buckets[server_details.get_server_string()] = TokenBucket(
67
+ if server_details.endpoint.id() not in self.server_buckets:
68
+ self.server_buckets[server_details.endpoint.id()] = TokenBucket(
69
69
  self.SERVER_LIMIT, self.SERVER_LIMIT, 1, self.SERVER_REFRESH_AMOUNT
70
70
  )
71
71
 
@@ -76,7 +76,7 @@ class RateLimiter:
76
76
  with self.lock:
77
77
  for bucket in [
78
78
  self.socket_buckets.get(server_details),
79
- self.server_buckets.get(server_details.get_server_string()),
79
+ self.server_buckets.get(server_details.endpoint.id()),
80
80
  ]:
81
81
  bucket.refresh()
82
82
  if not bucket.can_consume(amount):
@@ -90,14 +90,14 @@ class RateLimiter:
90
90
  with self.lock:
91
91
  for bucket in [
92
92
  self.socket_buckets.get(server_details),
93
- self.server_buckets.get(server_details.get_server_string()),
93
+ self.server_buckets.get(server_details.endpoint.id()),
94
94
  ]:
95
95
  bucket.refresh()
96
96
  if not bucket.can_consume(amount):
97
97
  raise RateLimitError("Not Enough Tokens")
98
98
  for bucket in [
99
99
  self.socket_buckets.get(server_details),
100
- self.server_buckets.get(server_details.get_server_string()),
100
+ self.server_buckets.get(server_details.endpoint.id()),
101
101
  ]:
102
102
  bucket.consume(amount)
103
103
 
@@ -112,7 +112,7 @@ class RateLimiter:
112
112
  delay = 0
113
113
  for bucket in [
114
114
  self.socket_buckets.get(server_details),
115
- self.server_buckets.get(server_details.get_server_string()),
115
+ self.server_buckets.get(server_details.endpoint.id()),
116
116
  ]:
117
117
  bucket.refresh()
118
118
  val = (
@@ -135,8 +135,6 @@ class RateLimiter:
135
135
  """
136
136
  with self.lock:
137
137
  del self.socket_buckets[server_details]
138
- server_str = server_details.get_server_string()
139
- if not any(
140
- d.get_server_string() == server_str for d in self.socket_buckets
141
- ):
138
+ server_str = server_details.endpoint.id()
139
+ if not any(d.endpoint.id() == server_str for d in self.socket_buckets):
142
140
  del self.server_buckets[server_str]
@@ -1,16 +1,14 @@
1
1
  import shlex
2
- import base64
3
2
  import betterproto
4
3
  from websockets.exceptions import InvalidURI, InvalidHandshake, ConnectionClosedError
5
4
  from websockets.legacy.client import WebSocketClientProtocol
6
5
  from websockets.client import connect
7
6
  from asyncio import TimeoutError, Task, AbstractEventLoop
8
- from typing import Union, Coroutine, Optional, Set, Dict
7
+ from typing import Coroutine, Optional, Set, Dict
9
8
  import logging
10
9
  import asyncio
11
10
 
12
11
  from ..camera import CameraManager
13
- from ..proxy import ProxyValueGrabber
14
12
  from ..rustplus_proto import AppMessage, AppRequest, AppError
15
13
  from ...commands import CommandOptions, ChatCommand, ChatCommandTime
16
14
  from ...events import (
@@ -21,7 +19,10 @@ from ...events import (
21
19
  )
22
20
  from ...events.clan_info_event import ClanInfoEventPayload
23
21
  from ...exceptions import RequestError
24
- from ...identification import ServerDetails, RegisteredListener
22
+ from ...identification import (
23
+ ServerDetails,
24
+ RegisteredListener,
25
+ )
25
26
  from ...structs import RustChatMessage, RustTeamInfo, RustClanInfo
26
27
  from ...utils import YieldingEvent, convert_time
27
28
  from ...utils.utils import error_present
@@ -33,33 +34,21 @@ class RustWebsocket:
33
34
  def __init__(
34
35
  self,
35
36
  server_details: ServerDetails,
36
- command_options: Union[CommandOptions, None],
37
- use_fp_proxy: bool,
38
- use_test_server: bool,
37
+ command_options: CommandOptions | None,
39
38
  debug: bool,
40
39
  ) -> None:
41
40
  self.server_details: ServerDetails = server_details
42
- self.command_options: Union[CommandOptions, None] = command_options
43
- self.connection: Union[WebSocketClientProtocol, None] = None
41
+ self.command_options: CommandOptions | None = command_options
42
+ self.connection: WebSocketClientProtocol | None = None
44
43
  self.logger: logging.Logger = logging.getLogger("rustplus.py")
45
- self.task: Union[Task, None] = None
44
+ self.task: Task | None = None
46
45
  self.debug: bool = debug
47
- self.use_test_server: bool = use_test_server
48
- self.use_fp_proxy: bool = use_fp_proxy
49
46
 
50
47
  self.responses: Dict[int, YieldingEvent] = {}
51
48
  self.open = False
52
49
 
53
50
  async def connect(self) -> bool:
54
-
55
- address = (
56
- (
57
- f"{'wss' if self.server_details.secure else 'ws'}://"
58
- + self.server_details.get_server_string()
59
- )
60
- if not self.use_fp_proxy
61
- else f"wss://companion-rust.facepunch.com/game/{self.server_details.ip}/{self.server_details.port}"
62
- ) + f"?v={ProxyValueGrabber.get_value()}"
51
+ address = self.server_details.endpoint.uri()
63
52
 
64
53
  try:
65
54
  self.connection = await connect(
@@ -67,6 +56,7 @@ class RustWebsocket:
67
56
  close_timeout=0,
68
57
  ping_interval=None,
69
58
  max_size=1_000_000_000,
59
+ **self.server_details.endpoint.connect_kwargs(),
70
60
  )
71
61
  except (InvalidURI, OSError, InvalidHandshake, TimeoutError) as err:
72
62
  self.logger.warning("WebSocket connection error: %s", err)
@@ -100,15 +90,25 @@ class RustWebsocket:
100
90
  async def run(self) -> None:
101
91
  while self.open:
102
92
  try:
103
- data = await self.connection.recv()
93
+ if self.connection is None:
94
+ self.logger.warning(
95
+ "No Current Websocket Connection, exiting run loop"
96
+ )
97
+ break
98
+
99
+ data: str | bytes = await self.connection.recv()
100
+
101
+ if isinstance(data, str):
102
+ # Text frame: not protobuf, so ignore it
103
+ self.logger.warning(
104
+ "Ignoring unexpected text frame (%d chars)", len(data)
105
+ )
106
+ continue
104
107
 
105
108
  await self.run_coroutine_non_blocking(
106
109
  self.run_proto_event(data, self.server_details)
107
110
  )
108
111
 
109
- if self.use_test_server:
110
- data = base64.b64decode(data)
111
-
112
112
  app_message = AppMessage()
113
113
  app_message.parse(data)
114
114
 
@@ -134,7 +134,7 @@ class RustWebsocket:
134
134
  e,
135
135
  )
136
136
 
137
- async def send_and_get(self, request: AppRequest) -> AppMessage:
137
+ async def send_and_get(self, request: AppRequest) -> AppMessage | None:
138
138
  if not await self.send_message(request):
139
139
  message = AppMessage()
140
140
  error = AppError()
@@ -158,19 +158,14 @@ class RustWebsocket:
158
158
  self.responses[request.seq] = YieldingEvent()
159
159
 
160
160
  try:
161
- if self.use_test_server:
162
- await self.connection.send(
163
- base64.b64encode(bytes(request)).decode("utf-8")
164
- )
165
- else:
166
- await self.connection.send(bytes(request))
161
+ await self.connection.send(bytes(request))
167
162
  except Exception as err:
168
163
  self.logger.warning("WebSocket connection error: %s", err)
169
164
  return False
170
165
 
171
166
  return True
172
167
 
173
- async def get_response(self, seq: int) -> Union[AppMessage, None]:
168
+ async def get_response(self, seq: int) -> AppMessage | None:
174
169
 
175
170
  response = await self.responses[seq].wait(timeout=self.RESPONSE_TIMEOUT)
176
171
  del self.responses[seq]
@@ -185,7 +180,9 @@ class RustWebsocket:
185
180
 
186
181
  if error_present(app_message):
187
182
 
188
- event: YieldingEvent = self.responses.get(app_message.response.seq, None)
183
+ event: YieldingEvent | None = self.responses.get(
184
+ app_message.response.seq, None
185
+ )
189
186
  if event is not None:
190
187
  if self.debug:
191
188
  self.logger.info(
@@ -315,7 +312,9 @@ class RustWebsocket:
315
312
 
316
313
  else:
317
314
  # This means that it wasn't sent by the server and is a message from the server in response to an action
318
- event: YieldingEvent = self.responses.get(app_message.response.seq, None)
315
+ event: YieldingEvent | None = self.responses.get(
316
+ app_message.response.seq, None
317
+ )
319
318
  if event is not None:
320
319
  if self.debug:
321
320
  self.logger.info(f"Running Response Event: {app_message}")
@@ -333,9 +332,7 @@ class RustWebsocket:
333
332
  return None
334
333
 
335
334
  @staticmethod
336
- async def run_proto_event(
337
- data: Union[str, bytes], server_details: ServerDetails
338
- ) -> None:
335
+ async def run_proto_event(data: str | bytes, server_details: ServerDetails) -> None:
339
336
  handlers: Set[RegisteredListener] = (
340
337
  ProtobufEventPayload.HANDLER_LIST.get_handlers(server_details)
341
338
  )
@@ -372,5 +369,5 @@ class RustWebsocket:
372
369
 
373
370
  @staticmethod
374
371
  async def run_coroutine_non_blocking(coroutine: Coroutine) -> Task:
375
- loop: AbstractEventLoop = asyncio.get_event_loop_policy().get_event_loop()
372
+ loop: AbstractEventLoop = asyncio.get_event_loop()
376
373
  return loop.create_task(coroutine)
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
2
  from collections import defaultdict
3
- from datetime import datetime
3
+ from datetime import datetime, timezone
4
4
  from importlib import resources
5
5
  from io import BytesIO
6
- from typing import List, Union
6
+ from typing import List
7
7
  import logging
8
8
  from PIL import Image
9
9
 
@@ -56,10 +56,8 @@ class RustSocket:
56
56
  def __init__(
57
57
  self,
58
58
  server_details: ServerDetails,
59
- ratelimiter: Union[RateLimiter, None] = None,
60
- command_options: Union[CommandOptions, None] = None,
61
- use_fp_proxy: bool = False,
62
- use_test_server: bool = False,
59
+ ratelimiter: RateLimiter | None = None,
60
+ command_options: CommandOptions | None = None,
63
61
  debug: bool = False,
64
62
  ) -> None:
65
63
  self.server_details = server_details
@@ -80,8 +78,6 @@ class RustSocket:
80
78
  self.ws = RustWebsocket(
81
79
  self.server_details,
82
80
  self.command_options,
83
- use_fp_proxy,
84
- use_test_server,
85
81
  debug,
86
82
  )
87
83
  self.seq = 1
@@ -143,7 +139,7 @@ class RustSocket:
143
139
  while True:
144
140
  await asyncio.sleep(1)
145
141
 
146
- async def get_time(self) -> Union[RustTime, RustError]:
142
+ async def get_time(self) -> RustTime | RustError:
147
143
  """
148
144
  Gets the current in-game time from the server.
149
145
 
@@ -183,7 +179,7 @@ class RustSocket:
183
179
 
184
180
  await self.ws.send_message(packet, True)
185
181
 
186
- async def get_info(self) -> Union[RustInfo, RustError]:
182
+ async def get_info(self) -> RustInfo | RustError:
187
183
  """
188
184
  Gets information on the Rust Server
189
185
  :return: RustInfo - The info of the server
@@ -200,7 +196,7 @@ class RustSocket:
200
196
 
201
197
  return RustInfo(response.response.info)
202
198
 
203
- async def get_team_chat(self) -> Union[List[RustChatMessage], RustError]:
199
+ async def get_team_chat(self) -> List[RustChatMessage] | RustError:
204
200
  """
205
201
  Gets the team chat from the server
206
202
 
@@ -220,7 +216,7 @@ class RustSocket:
220
216
  RustChatMessage(message) for message in response.response.team_chat.messages
221
217
  ]
222
218
 
223
- async def get_team_info(self) -> Union[RustTeamInfo, RustError]:
219
+ async def get_team_info(self) -> RustTeamInfo | RustError:
224
220
  """
225
221
  Gets Information on the members of your team
226
222
 
@@ -238,7 +234,7 @@ class RustSocket:
238
234
 
239
235
  return RustTeamInfo(response.response.team_info)
240
236
 
241
- async def get_markers(self) -> Union[List[RustMarker], RustError]:
237
+ async def get_markers(self) -> List[RustMarker] | RustError:
242
238
  """
243
239
  Gets all the map markers from the server
244
240
 
@@ -262,9 +258,9 @@ class RustSocket:
262
258
  add_events: bool = False,
263
259
  add_vending_machines: bool = False,
264
260
  add_team_positions: bool = False,
265
- override_images: dict = None,
261
+ override_images: dict | None = None,
266
262
  add_grid: bool = False,
267
- ) -> Union[Image.Image, RustError]:
263
+ ) -> Image.Image | RustError:
268
264
  """
269
265
  Gets an image of the map from the server with the specified additions
270
266
 
@@ -308,7 +304,9 @@ class RustSocket:
308
304
  output = output.crop(
309
305
  (500, 500, map_packet.height - 500, map_packet.width - 500)
310
306
  )
311
- output = output.resize((map_size, map_size), Image.LANCZOS).convert("RGBA")
307
+ output = output.resize((map_size, map_size), Image.Resampling.LANCZOS).convert(
308
+ "RGBA"
309
+ )
312
310
 
313
311
  if add_grid:
314
312
  output.paste(grid := generate_grid(map_size), (5, 5), grid)
@@ -326,7 +324,7 @@ class RustSocket:
326
324
  if str(monument.token) == "DungeonBase":
327
325
  continue
328
326
  if "underwater-lab-base" in str(monument.token):
329
- # An underwater lab's interior modules (moonpools, etc.) are
327
+ # An underwater lab's interior modules (moon pools, etc.) are
330
328
  # reported as separate markers next to the lab; they aren't
331
329
  # standalone monuments, so don't draw them.
332
330
  continue
@@ -387,7 +385,7 @@ class RustSocket:
387
385
 
388
386
  return output
389
387
 
390
- async def get_map_info(self) -> Union[RustMap, RustError]:
388
+ async def get_map_info(self) -> RustMap | RustError:
391
389
  """
392
390
  Gets the raw map data from the server
393
391
 
@@ -405,9 +403,7 @@ class RustSocket:
405
403
 
406
404
  return RustMap(response.response.map)
407
405
 
408
- async def get_entity_info(
409
- self, eid: int = None
410
- ) -> Union[RustEntityInfo, RustError]:
406
+ async def get_entity_info(self, eid: int) -> RustEntityInfo | RustError:
411
407
  """
412
408
  Gets entity info from the server
413
409
 
@@ -459,7 +455,7 @@ class RustSocket:
459
455
 
460
456
  await self.ws.send_message(packet, True)
461
457
 
462
- async def check_subscription_to_entity(self, eid: int) -> Union[bool, RustError]:
458
+ async def check_subscription_to_entity(self, eid: int) -> bool | RustError:
463
459
  """
464
460
  Checks if you are subscribed to an entity
465
461
 
@@ -481,7 +477,7 @@ class RustSocket:
481
477
 
482
478
  return response.response.flag.value
483
479
 
484
- async def promote_to_team_leader(self, steamid: int = None) -> None:
480
+ async def promote_to_team_leader(self, steamid: int) -> None:
485
481
  """
486
482
  Promotes a given user to the team leader by their 64-bit Steam ID
487
483
 
@@ -496,8 +492,8 @@ class RustSocket:
496
492
  await self.ws.send_message(packet, True)
497
493
 
498
494
  async def get_contents(
499
- self, eid: int = None, combine_stacks: bool = False
500
- ) -> Union[RustContents, RustError]:
495
+ self, eid: int, combine_stacks: bool = False
496
+ ) -> RustContents | RustError:
501
497
  """
502
498
  Gets the contents of a storage monitor-attached container
503
499
 
@@ -510,8 +506,10 @@ class RustSocket:
510
506
  if isinstance(returned_data, RustError):
511
507
  return returned_data
512
508
 
513
- target_time = datetime.utcfromtimestamp(int(returned_data.protection_expiry))
514
- difference = target_time - datetime.utcnow()
509
+ target_time = datetime.fromtimestamp(
510
+ int(returned_data.protection_expiry), tz=timezone.utc
511
+ )
512
+ difference = target_time - datetime.now(timezone.utc)
515
513
 
516
514
  items = []
517
515
 
@@ -552,13 +550,13 @@ class RustSocket:
552
550
 
553
551
  return RustContents(difference, bool(returned_data.has_protection), items)
554
552
 
555
- async def get_camera_manager(self, cam_id: str) -> Union[CameraManager, RustError]:
553
+ async def get_camera_manager(self, cam_id: str) -> CameraManager | RustError:
556
554
  """
557
555
  Gets a camera manager for a given camera ID
558
556
 
559
557
  NOTE: This will override the current camera manager if one exists for the given ID so you cannot have multiple
560
558
 
561
- :param cam_id: The ID of the camera
559
+ :param cam_id: The ID of the target camera
562
560
  :return CameraManager: The camera manager
563
561
  :raises RequestError: If the camera is not found, or you cannot access it. See reason for more info
564
562
  """
@@ -576,7 +574,7 @@ class RustSocket:
576
574
 
577
575
  return CameraManager(self, cam_id, response.response.camera_subscribe_info)
578
576
 
579
- async def get_clan_info(self) -> Union[RustClanInfo, RustError]:
577
+ async def get_clan_info(self) -> RustClanInfo | RustError:
580
578
  """
581
579
  Gets the clan information for the player's current clan.
582
580
 
@@ -594,7 +592,7 @@ class RustSocket:
594
592
 
595
593
  return RustClanInfo(response.response.clan_info.clan_info)
596
594
 
597
- async def get_clan_chat(self) -> Union[List[RustClanMessage], RustError]:
595
+ async def get_clan_chat(self) -> List[RustClanMessage] | RustError:
598
596
  """
599
597
  Gets the clan chat for the player's current clan.
600
598
 
@@ -642,7 +640,7 @@ class RustSocket:
642
640
 
643
641
  await self.ws.send_message(packet, True)
644
642
 
645
- async def get_nexus_auth(self, app_key: str) -> Union[RustAuthDetails, RustError]:
643
+ async def get_nexus_auth(self, app_key: str) -> RustAuthDetails | RustError:
646
644
  """
647
645
  Gets the auth for a server. Does not require that the player token of this RustSocket is set correctly.
648
646
 
@@ -667,7 +665,7 @@ class RustSocket:
667
665
  response.response.nexus_auth.player_token,
668
666
  )
669
667
 
670
- async def kick_from_team(self, steamid: int) -> Union[None, RustError]:
668
+ async def kick_from_team(self, steamid: int) -> None | RustError:
671
669
  """
672
670
  Kicks a player from the team by their 64-bit Steam ID
673
671
 
@@ -1,10 +1,9 @@
1
- from typing import Union
2
1
  from ..remote.rustplus_proto import AppTeamMessage, AppClanMessage
3
2
  from .serialization import Serializable
4
3
 
5
4
 
6
5
  class RustChatMessage(Serializable):
7
- def __init__(self, data: Union[AppTeamMessage, AppClanMessage]):
6
+ def __init__(self, data: AppTeamMessage | AppClanMessage):
8
7
  self._steam_id: int = data.steam_id
9
8
  self._name: str = data.name
10
9
  self._message: str = data.message
@@ -1,10 +1,9 @@
1
- from typing import Union
2
1
  from .serialization import Serializable
3
2
 
4
3
 
5
4
  class RustItem(Serializable):
6
5
  def __init__(
7
- self, name: str, item_id: Union[str, int], quantity: int, is_blueprint: bool
6
+ self, name: str, item_id: str | int, quantity: int, is_blueprint: bool
8
7
  ) -> None:
9
8
  self._name: str = name
10
9
  self._item_id: int = int(item_id)