|
1 | 1 | import os
|
2 |
| -from threading import Lock |
| 2 | +from threading import Lock, Thread |
| 3 | +import time |
| 4 | +from typing import Callable, Optional |
| 5 | +from anyio import Event |
3 | 6 |
|
4 | 7 | from jproperties import Properties
|
5 | 8 |
|
|
8 | 11 | from .utils import logger, psi, rtr
|
9 | 12 |
|
10 | 13 |
|
| 14 | +class StatsChecker(Thread): |
| 15 | + def __init__(self, interval: int, cb: Callable[[], None]): |
| 16 | + super().__init__() |
| 17 | + self.setDaemon(True) |
| 18 | + self.setName(self.__class__.__name__) |
| 19 | + self._report_time = time.time() |
| 20 | + self.stop_event = Event() |
| 21 | + self.interval = interval |
| 22 | + self._callback = cb |
| 23 | + |
| 24 | + def run(self): |
| 25 | + while True: # loop until stop |
| 26 | + while True: # # loop for report |
| 27 | + if self.stop_event.wait(1): |
| 28 | + return |
| 29 | + if time.time() - self._report_time > self.interval: |
| 30 | + break |
| 31 | + self._report_time = time.time() |
| 32 | + self._callback() |
| 33 | + |
| 34 | + def stop(self): |
| 35 | + self.stop_event.set() |
| 36 | + |
11 | 37 | class MountSlot:
|
12 | 38 | def __init__(self, path):
|
13 | 39 | self.path = path
|
14 | 40 | self.load_config()
|
15 | 41 | self.properties = Properties()
|
16 | 42 | self.slot_lock = Lock()
|
| 43 | + self.__players = [] |
| 44 | + self.__players_lock = Lock() |
| 45 | + self.__stats_lock = Lock() |
| 46 | + self.__stats_checker = StatsChecker(60, self.update_stats) |
17 | 47 |
|
18 | 48 | @property
|
19 | 49 | def name(self):
|
@@ -88,3 +118,48 @@ def edit_config(self, key: str, value: str):
|
88 | 118 | self._config.__setattr__(key, value)
|
89 | 119 | self.save_config()
|
90 | 120 | return rtr('config.set_value', key=rtr(f'config.slot.{key}'), value=self._config.__getattribute__(key))
|
| 121 | + |
| 122 | + def on_player_join(self, player: str): |
| 123 | + with self.__players_lock: |
| 124 | + self.update_stats() |
| 125 | + self._config.stats.total_players = self._config.stats.total_players + 1 |
| 126 | + self.__players.append(player) |
| 127 | + self.update_stats() |
| 128 | + |
| 129 | + def on_player_left(self, player: str): |
| 130 | + try: |
| 131 | + with self.__players_lock: |
| 132 | + self.update_stats() |
| 133 | + self.__players.remove(player) |
| 134 | + except ValueError: |
| 135 | + pass |
| 136 | + |
| 137 | + def on_mount(self): |
| 138 | + if not self.__stats_checker.is_alive: |
| 139 | + with self.__stats_lock: |
| 140 | + current = time.time_ns |
| 141 | + self._config.stats.last_mount_ns = current |
| 142 | + self.save_config() |
| 143 | + self.__stats_checker.start() |
| 144 | + |
| 145 | + def on_unmount(self): |
| 146 | + if self.__stats_checker.is_alive: |
| 147 | + self.update_stats() |
| 148 | + self.__stats_checker.stop() |
| 149 | + self.__stats_checker.join() |
| 150 | + |
| 151 | + |
| 152 | + def update_stats(self): |
| 153 | + if not self.__stats_checker.is_alive: |
| 154 | + return |
| 155 | + with self.__stats_lock: |
| 156 | + current = time.time_ns |
| 157 | + prev = self._config.stats.last_mount_ns |
| 158 | + p = len(self.__players) |
| 159 | + t = current - prev |
| 160 | + stats = self._config.stats |
| 161 | + stats.last_mount_ns = current |
| 162 | + stats.total_use_time = stats.total_use_time + t |
| 163 | + stats.total_player_time = stats.total_player_time + t * p |
| 164 | + self._config.stats = stats |
| 165 | + self.save_config() |
0 commit comments