erepublik-ebot/ebot/helpers.py
2022-07-04 10:44:45 +03:00

213 lines
6.2 KiB
Python

""" eBot
Copyright (C) 2022 Eriks K
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
from datetime import datetime
from operator import attrgetter
from typing import Any, Dict, List, NamedTuple, NoReturn, Optional, Tuple, Union
from erepublik._logging import ErepublikErrorHTTTPHandler
from erepublik.classes import ErepublikException
from erepublik.constants import max_datetime
DMG_MAP: Dict[int, Tuple[int, int]] = {
1: (6_000_000, 12_000_000),
2: (12_000_000, 18_000_000),
3: (18_000_000, 24_000_000),
4: (60_000_000, 90_000_000),
11: (80_000, 100_000),
}
class _EmptyMedal:
def __init__(
self,
time: datetime,
battle_id: int,
division_id: int,
defender_side: bool,
zone: int,
second_attempt: bool = False,
):
self.time: datetime = time
self.division_id: int = division_id
self.battle_id: int = battle_id
self.defender_side: bool = bool(defender_side)
self.round: int = zone
self.second_attempt: bool = second_attempt
@property
def _sort_sequence(self):
return self.time, not self.defender_side, -self.round, self.battle_id, self.division_id
def __hash__(self):
return hash((self.battle_id, self.division_id))
@property
def __dict__(self):
return dict(
time=self.time,
battle_id=self.battle_id,
division_id=self.division_id,
round=self.round,
defender_side=self.defender_side,
second_attempt=self.second_attempt,
)
def __repr__(self):
return self.__str__()
def __str__(self):
return (
f"_EmptyMedal(time={self.time.strftime('%F %T')}, battle_id={self.battle_id}, "
f"division_id={self.division_id}, defender_side={self.defender_side}, round={self.round})"
)
def __eq__(self, other):
try:
return (self.battle_id, self.division_id) == (other.battle_id, other.division_id)
except AttributeError:
return False
def __ne__(self, other):
try:
return not self.__eq__(other)
except AttributeError:
return True
@property
def as_dict(self):
return self.__dict__
class Task(NamedTuple):
name: str
time: datetime
priority: bool = False
def __repr__(self):
return f"{self.time.strftime('%F %T')} {self.human_name}" + (" (P)" if self.priority else "")
@property
def human_name(self) -> str:
return " ".join(self.name.split("_")).capitalize()
class Tasks:
__storage: List[Task]
_defaults: Dict[str, any]
def __repr__(self):
return f"<class Tasks: {len(self.__storage)} in queue>"
def __init__(self):
self.__storage = []
self._defaults = {}
def __getitem__(self, key: Union[str, int]) -> Optional[Task]:
try:
if isinstance(key, int):
return self.__storage[key]
for task in self.__storage:
if task.name == key:
return task
except IndexError:
return Task("Do nothing", max_datetime)
def __setitem__(self, key: Union[str, int], value: Union[datetime, Tuple[datetime, bool]]) -> NoReturn:
priority = False
if isinstance(value, tuple):
value, priority = value
if isinstance(key, int) and isinstance(value, datetime):
old_item = self.__storage.pop(key)
item = Task(old_item.name, value, priority)
elif isinstance(key, str) and isinstance(value, datetime):
item = Task(key, value, priority)
task_idx = self.__get_key_index(key)
if task_idx is not None:
self.__storage.pop(task_idx)
else:
raise TypeError(
f"key, value pairs must be of types (int, datetime) or (str, datetime) "
f"not ({type(key)}, {type(value)})"
)
self.__storage.append(item)
def __get_key_index(self, key: str) -> Optional[int]:
for idx, task in enumerate(self.__storage):
if task.name == key:
return idx
return None
def append(self, __object: Task) -> None:
if not isinstance(__object, Task):
raise TypeError(f"object must be of instance Task, not {type(__object)}")
self.__storage.append(__object)
def sort(self) -> NoReturn:
self.__storage.sort(key=attrgetter("name"))
self.__storage.sort(key=attrgetter("priority"), reverse=True)
self.__storage.sort(key=attrgetter("time"))
def pop(self, key: str) -> Optional[Task]:
_idx = self.__get_key_index(key)
if isinstance(_idx, int):
return self.__storage.pop(_idx)
else:
return
def __iter__(self):
for task in self.__storage:
yield task
def set_default(self, key: str, value: Any) -> NoReturn:
self._defaults[key] = value
def get_default(self, key: str, default: Any = None) -> Any:
return self._defaults.get(key, default)
@property
def as_dict(self):
return {"tasks": self.__storage, "defaults": self._defaults}
class BotStop(SystemExit):
pass
class BotRestart(ErepublikException):
pass
class EbotErrorHttpHandler(ErepublikErrorHTTTPHandler):
def __init__(self):
logging.Handler.__init__(self, level=logging.ERROR)
self._reporter = None
self.host = "erep.lv"
self.url = "/ebot/error/"
self.method = "POST"
self.secure = True
self.credentials = ("0", "changeme")
self.context = None
def _get_last_response(self):
return {}
def _get_instance_json(self):
return ""