213 lines
6.2 KiB
Python
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 ""
|