Skip to content

Commit a58db0c

Browse files
committed
Enhance server creation process by adding 'started_at' field and improve error handling for bus configuration
1 parent 55d3e8b commit a58db0c

5 files changed

Lines changed: 53 additions & 56 deletions

File tree

client/src/dashboard/dashboard.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ async function on_create_server_button() {
141141
autostart: autostart,
142142
ram: parseInt(ram, 10), // Convert to integer
143143
mc_version: mc_version,
144-
modloader_version: modloader_version
144+
modloader_version: modloader_version,
145+
started_at: null,
145146
};
146147
const success = await API.create_server(server_info);
147148
if (success) {

forge-server-manager.code-workspace

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
"*.template": "html",
2121
"python.h": "c",
2222
"*/config.json": "jsonc"
23-
}
23+
},
24+
"python.analysis.inlayHints.callArgumentNames": "partial",
25+
"python.analysis.inlayHints.functionReturnTypes": true,
26+
"python.analysis.typeCheckingMode": "basic"
2427
}
2528
}

server/src/bus/bus.py

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def __check_callback(self, event: Event, callback: Callback):
7575
)
7676
if arg_type.__name__ != event[arg_name].type:
7777
raise ValueError(
78-
f"Callback for event {event.name} has argument {arg_name} with wrong type (expected {event.args[arg_name].type}, got {arg_type.__name__})"
78+
f"Callback for event {event.name} has argument {arg_name} with wrong type (expected {event[arg_name].type}, got {arg_type.__name__})"
7979
)
8080

8181
def __register(self, event: Event, callback: Callback):
@@ -117,10 +117,10 @@ def __read_prefix(self, encoded: str) -> tuple[BusMessagePrefix, str]:
117117
prefix = BusMessagePrefix.from_string(prefix_str)
118118
return prefix, data
119119

120-
def __write(self, raw_msg: str, __to : int, fragment_number: int, fragment_count: int, msg_id : int):
120+
def __write(self, raw_msg: str, _to : int, fragment_number: int, fragment_count: int, msg_id : int):
121121
# add the id at the beginning, followed by a 0 for the target
122122
prefix = BusMessagePrefix(source_id=self.__id,
123-
target_id=__to,
123+
target_id=_to,
124124
message_id=msg_id,
125125
fragment_number=fragment_number,
126126
fragment_count=fragment_count)
@@ -138,7 +138,7 @@ def __write(self, raw_msg: str, __to : int, fragment_number: int, fragment_count
138138
else:
139139
raise ValueError("No free position in shared list to send data.")
140140

141-
def __send(self, event: Event, __to : int, timeout : int = 5, **kwargs: Any) -> Any:
141+
def __send(self, event: Event, _to : int, timeout : float = 5, **kwargs: Any) -> Any:
142142
if "timestamp" not in kwargs:
143143
for a in event.args:
144144
if a.name == "timestamp" and a.type == "datetime":
@@ -160,7 +160,7 @@ def __send(self, event: Event, __to : int, timeout : int = 5, **kwargs: Any) ->
160160
message_id = random.randint(0, 255) # Generate a random message ID for the event
161161

162162
for i, part in enumerate(parts):
163-
self.__write(part, __to, i, len(parts), message_id)
163+
self.__write(part, _to, i, len(parts), message_id)
164164

165165
if event.return_type != "None":
166166
res = self.wait_for(event.return_event(), timeout=timeout) # Wait for the event to be processed and return the result
@@ -173,7 +173,7 @@ def __send(self, event: Event, __to : int, timeout : int = 5, **kwargs: Any) ->
173173
Logger.debug(f"Event {event.name} triggered without return type, no waiting for result.")
174174
return None
175175

176-
def trigger(self, event: Event, timeout : int = 5, **kwargs: Any) -> Any:
176+
def trigger(self, event: Event, timeout : float = 5, **kwargs: Any) -> Any:
177177
"""
178178
Trigger an event with the given name and arguments.
179179
If the event requires a timestamp and it is not provided, it will be added automatically.
@@ -295,36 +295,3 @@ def stop(self):
295295
self.__thread.join()
296296
else:
297297
Logger.warning("Bus is not listening")
298-
299-
300-
301-
302-
303-
304-
305-
306-
307-
308-
309-
310-
if __name__ == "__main__":
311-
from datetime import datetime
312-
bus1 = Bus()
313-
314-
def _get_players_1(timestamp: datetime, server_name: str) -> list[str]:
315-
if server_name == "TestServer":
316-
return ["Player1", "Player2", "Player3"]
317-
return None
318-
319-
def _get_players_2(timestamp: datetime, server_name: str) -> list[str]:
320-
if server_name == "TestServer2":
321-
return ["Player4", "Player5", "Player6"]
322-
return None
323-
324-
325-
bus1.register(Events["PLAYERS.LIST"], _get_players_1)
326-
bus1.register(Events["PLAYERS.LIST"], _get_players_2)
327-
328-
329-
bus2 = Bus()
330-
print(bus2.trigger(Events["PLAYERS.LIST"], timestamp=datetime.now(), server_name="TestServer2"))

server/src/bus/events.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ def __load_events(self, xml_path: str):
237237
raise ValueError(f"Failed to parse XML file {xml_path}: {e}") from None
238238
root = tree.getroot()
239239
for namespace in root.findall('namespace'):
240-
self.__parse_namespace(namespace, namespace.get('name'))
240+
self.__parse_namespace(namespace, namespace.get('name') or "global")
241241
Logger.info(f"Loaded {len(self.events)} events from XML file.")
242242

243243
def __parse_namespace(self, namespace : ET.Element, namespace_name: str):
@@ -249,18 +249,18 @@ def __parse_namespace(self, namespace : ET.Element, namespace_name: str):
249249
)
250250
for event in namespace.findall('event'):
251251
event_name = f"{namespace_name}.{event.get('name')}"
252-
event_id = int(event.get('id'), 16)
252+
event_id = int(event.get('id'), 16) #type: ignore
253253
if not event_id:
254254
raise ValueError(f"Event {event_name} does not have an ID")
255255
args = [
256-
EventArg(arg.get('name'), arg.get('type'), int(arg.get('id', 0), 16))
257-
for arg in event.find('args').findall('arg')
256+
EventArg(arg.get('name'), arg.get('type'), int(arg.get('id', 0), 16)) #type: ignore
257+
for arg in event.find('args').findall('arg') #type: ignore
258258
]
259-
return_type = event.find('return').get('type')
259+
return_type = event.find('return').get('type') #type: ignore
260260
Logger.debug(f"Registering event: {event_name} (ID: {event_id})")
261261
if event_id in self.events:
262262
Logger.warning(f"Event ID {event_id} already exists, overwriting: {self.events[event_id].name} -> {event_name}")
263-
self.events[event_id] = Event(event_name, event_id, args, return_type)
263+
self.events[event_id] = Event(event_name, event_id, args, return_type) #type: ignore
264264

265265
def __getitem__(self, item: str|int) -> Event:
266266
if isinstance(item, str):

server/src/core/core.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,18 @@ def __init__(self, config_file: str):
2525
self.__running = False
2626

2727
# Initialize the bus dispatcher (will run in a separate thread)
28-
self.__bus_dispatcher = BusDispatcher(
29-
self.__config.get("bus.memory_size", default=8, set_if_not_found=True),
30-
self.__config.get("bus.max_string_length", default=8192, set_if_not_found=True) # default of 8KB
31-
)
28+
29+
mem_size = self.__config.get("bus.memory_size", default=8, set_if_not_found=True)
30+
max_str_len = self.__config.get("bus.max_string_length", default=8192, set_if_not_found=True) # default of 8KB
31+
32+
if not isinstance(mem_size, int) or mem_size <= 0:
33+
Logger.error(f"Invalid bus memory size: {mem_size}. Must be a positive integer. Using default of 8MB.")
34+
raise ValueError("Invalid bus memory size in configuration.")
35+
if not isinstance(max_str_len, int) or max_str_len <= 0:
36+
Logger.error(f"Invalid bus max string length: {max_str_len}. Must be a positive integer. Using default of 8192 bytes.")
37+
raise ValueError("Invalid bus max string length in configuration.")
38+
39+
self.__bus_dispatcher = BusDispatcher( mem_size, max_str_len)
3240
self.__bus_dispatcher_thread = th.Thread(
3341
target=self.__bus_dispatcher.mainloop,
3442
daemon=True,
@@ -38,7 +46,7 @@ def __init__(self, config_file: str):
3846
# Initialize the bus to communicate with modules through the dispatcher
3947
bus_data = self.__bus_dispatcher.get_bus_data("core")
4048
self.__bus = Bus(bus_data)
41-
self._srv_config = JSONConfig(self.__config.get("server_config_path"))
49+
self._srv_config = JSONConfig(str(self.__config.get("server_config_path")))
4250

4351
self.__ui_processes: Dict[str, mp.Process] = {}
4452
self.__mc_servers : Dict[str, mp.Process] = {}
@@ -98,7 +106,7 @@ def __start_user_interfaces(self):
98106
Initializes and start user interface modules based on the configuration.
99107
This method is called when the core is started.
100108
"""
101-
to_load : dict[str, dict[str, Any]] = self.__config.get("user_interface_modules")
109+
to_load : dict[str, dict[str, Any]] = self.__config.get("user_interface_modules") #type: ignore
102110
for module_type, config in to_load.items():
103111
Logger.info(f"Initializing user interface module {config['name']} of type {module_type}...")
104112
if module_type not in UserInterfaceModules:
@@ -175,11 +183,26 @@ def __start_server(self, server_name: str):
175183
try:
176184
server_type = self._srv_config.get(f"{server_name}.type")
177185
server_path = self._srv_config.get(f"{server_name}.path")
186+
187+
if not isinstance(server_type, str) or server_type not in McServersModules:
188+
Logger.error(f"Invalid or unknown server type for server {server_name}. Cannot start server.")
189+
return
190+
if not isinstance(server_path, str) or not os.path.exists(server_path):
191+
Logger.error(f"Invalid or non-existent server path for server {server_name}. Cannot start server.")
192+
return
178193

179194
Server = McServersModules[server_type]
180195
bus_data = self.__bus_dispatcher.get_bus_data(server_name)
181196
ram = self._srv_config.get(f"{server_name}.ram", default=1024, set_if_not_found=True)
182-
mc_version = Version.from_string(self._srv_config.get(f"{server_name}.mc_version"))
197+
if not isinstance(ram, int) or ram <= 0:
198+
Logger.error(f"Invalid RAM value for server {server_name}. Cannot start server.")
199+
return
200+
mc_version_raw = self._srv_config.get(f"{server_name}.mc_version")
201+
if not isinstance(mc_version_raw, str):
202+
Logger.error(f"Invalid Minecraft version for server {server_name}. Cannot start server.")
203+
return
204+
mc_version = Version.from_string(mc_version_raw)
205+
183206
def __start_mc_server():
184207
srv = Server(server_name, server_path, ram, mc_version, bus_data)
185208
srv.start()
@@ -290,7 +313,7 @@ def __get_server_status(self, server_name: str) -> ServerStatus:
290313
"""
291314
if server_name not in self._srv_config:
292315
Logger.error(f"Server {server_name} not found.")
293-
return False
316+
return ServerStatus.STOPPED
294317

295318
pinged : str = self.__bus.trigger(
296319
Events['SERVER.PING'],
@@ -303,8 +326,11 @@ def __get_mc_dirs(self) -> List[str]:
303326
try:
304327
data = []
305328
Logger.trace("Fetching Minecraft server directories from configuration.")
306-
for i in range(len(self.__config.get("minecraft_servers_dirs", []))):
329+
for i in range(len(self.__config.get("minecraft_servers_dirs", []))): # type: ignore
307330
dir_path = self.__config.get(f"minecraft_servers_dirs.{i}")
331+
if not isinstance(dir_path, str):
332+
Logger.warning(f"Invalid directory path at index {i}: {dir_path}. Skipping.")
333+
continue
308334
data.append(os.path.normpath(dir_path))
309335
Logger.trace(f"Found Minecraft server directories: {data}")
310336
return data

0 commit comments

Comments
 (0)