#292_shutdown_procedure #321

Merged
edraft merged 6 commits from #292_shutdown_procedure into 1.1.0 2023-07-18 11:03:16 +02:00
4 changed files with 384 additions and 340 deletions

View File

@ -10,6 +10,7 @@ from cpl_translation import TranslatePipe, TranslationServiceABC, TranslationSet
from bot_api.api_thread import ApiThread
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings
from bot_core.service.data_integrity_service import DataIntegrityService
class Application(DiscordBotApplicationABC):
@ -21,6 +22,7 @@ class Application(DiscordBotApplicationABC):
# cpl-core
self._logger: LoggerABC = services.get_service(LoggerABC)
self._data_integrity: DataIntegrityService = services.get_service(DataIntegrityService)
# cpl-discord
self._bot: DiscordBotServiceABC = services.get_service(DiscordBotServiceABC)
self._bot_settings: DiscordBotSettings = config.get_configuration(DiscordBotSettings)
@ -69,6 +71,7 @@ class Application(DiscordBotApplicationABC):
self._api.stop()
await self._bot.close()
self._data_integrity.check_data_integrity(is_for_shutdown=True)
self._logger.info(__name__, f"Stopped {DiscordBotService.__name__}")
except Exception as e:
self._logger.error(__name__, "stop failed", e)
@ -76,4 +79,4 @@ class Application(DiscordBotApplicationABC):
Console.write_line()
def is_restart(self):
return True if self._configuration.get_configuration("IS_RESTART") == "true" else False #
return True if self._configuration.get_configuration("IS_RESTART") == "true" else False

View File

@ -11,6 +11,7 @@ from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
from bot_core.events.core_on_ready_event import CoreOnReadyEvent
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
from bot_core.service.client_utils_service import ClientUtilsService
from bot_core.service.data_integrity_service import DataIntegrityService
from bot_core.service.message_service import MessageService
@ -24,6 +25,7 @@ class CoreModule(ModuleABC):
def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC):
services.add_transient(MessageServiceABC, MessageService)
services.add_transient(ClientUtilsABC, ClientUtilsService)
services.add_transient(DataIntegrityService)
# pipes
services.add_transient(DateTimeOffsetPipe)

View File

@ -0,0 +1,373 @@
from datetime import datetime, timedelta
from typing import Union
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.logging.database_logger import DatabaseLogger
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
from bot_data.abc.user_joined_voice_channel_repository_abc import (
UserJoinedVoiceChannelRepositoryABC,
)
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.client import Client
from bot_data.model.known_user import KnownUser
from bot_data.model.server import Server
from bot_data.model.user import User
from bot_data.model.user_joined_server import UserJoinedServer
from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from bot_data.service.seeder_service import SeederService
from bot_data.service.user_repository_service import ServerRepositoryABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class DataIntegrityService:
def __init__(
self,
config: ConfigurationABC,
logger: DatabaseLogger,
seeder: SeederService,
bot: DiscordBotServiceABC,
db_context: DatabaseContextABC,
server_repo: ServerRepositoryABC,
user_repo: UserRepositoryABC,
client_repo: ClientRepositoryABC,
known_users: KnownUserRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
user_joined_gs: UserJoinedGameServerRepositoryABC,
dtp: DateTimeOffsetPipe,
):
self._config = config
self._logger = logger
self._seeder = seeder
self._bot = bot
self._db_context = db_context
self._servers = server_repo
self._users = user_repo
self._clients = client_repo
self._known_users = known_users
self._user_joins = user_joins
self._user_joins_vc = user_joins_vc
self._user_joined_gs = user_joined_gs
self._dtp = dtp
self._is_for_shutdown = False
def _check_known_users(self):
self._logger.debug(__name__, f"Start checking KnownUsers table, {len(self._bot.users)}")
for u in self._bot.users:
u: discord.User = u
try:
if u.bot:
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._known_users.find_user_by_discord_id(u.id)
if user is not None:
continue
self._logger.warn(__name__, f"Unknown user: {u.id}")
self._logger.debug(__name__, f"Add user: {u.id}")
self._known_users.add_user(KnownUser(u.id))
self._db_context.save_changes()
user = self._known_users.find_user_by_discord_id(u.id)
if user is None:
self._logger.fatal(__name__, f"Cannot add user: {u.id}")
Ebola-Chan marked this conversation as resolved
Review

Wenn user None ist, dann wird _logger.fatal und danach _logger.debug aufgerufen. Da fehlt ein continue

if user is None:
    self._logger.fatal(__name__, f"Cannot add user: {u.id}")
    continue #<== Hier fehlt das continue
    
self._logger.debug(__name__, f"Added user: {u.id}")
Wenn ```user``` None ist, dann wird ```_logger.fatal``` und danach ```_logger.debug``` aufgerufen. Da fehlt ein ```continue``` ```python if user is None: self._logger.fatal(__name__, f"Cannot add user: {u.id}") continue #<== Hier fehlt das continue self._logger.debug(__name__, f"Added user: {u.id}") ```
Review

fatal ist ein Prozess ende
Siehe cpl logger_service.py:230-249

fatal ist ein Prozess ende Siehe cpl logger_service.py:230-249
self._logger.debug(__name__, f"Added user: {u.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get user", e)
Review

Die Fehlermeldung "Cannot get user" ist für mich zu ungenau. Was ist wenn es zu einem Fehler kommt, wenn der Bot versucht den User zu speichern?

Wie wäre es mit: "An error occurred while checking for known users"?

Die Fehlermeldung "Cannot get user" ist für mich zu ungenau. Was ist wenn es zu einem Fehler kommt, wenn der Bot versucht den User zu speichern? Wie wäre es mit: "An error occurred while checking for known users"?
def _check_servers(self):
self._logger.debug(__name__, f"Start checking Servers table")
for g in self._bot.guilds:
g: discord.Guild = g
try:
server = self._servers.find_server_by_discord_id(g.id)
if server is not None:
continue
self._logger.warn(__name__, f"Server not found in database: {g.id}")
self._logger.debug(__name__, f"Add server: {g.id}")
self._servers.add_server(Server(g.id))
self._db_context.save_changes()
server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Cannot add server: {g.id}")
edraft marked this conversation as resolved
Review

Auch hier fehlt ein continue

Auch hier fehlt ein ```continue```
self._logger.debug(__name__, f"Added server: {g.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get server", e)
Review

Fehlermeldung auch hier zu allgemein.

"An error occurred while checking servers"?

Fehlermeldung auch hier zu allgemein. "An error occurred while checking servers"?
results = self._servers.get_servers()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Servers is empty!")
def _check_clients(self):
self._logger.debug(__name__, f"Start checking Clients table")
for g in self._bot.guilds:
g: discord.Guild = g
try:
server: Server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
client = self._clients.find_client_by_server_id(server.id)
if client is not None:
continue
self._logger.warn(
__name__,
f"Client for server {g.id} not found in database: {self._bot.user.id}",
)
self._logger.debug(__name__, f"Add client: {self._bot.user.id}")
self._clients.add_client(Client(self._bot.user.id, 0, 0, 0, 0, 0, server))
self._db_context.save_changes()
client = self._clients.find_client_by_server_id(server.id)
if client is None:
self._logger.fatal(
__name__,
f"Cannot add client {self._bot.user.id} for server {g.id}",
)
edraft marked this conversation as resolved
Review

Hier fehlt wieder ein continue

Hier fehlt wieder ein ```continue```
self._logger.debug(__name__, f"Added client: {g.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get client", e)
Review

"An error occurred while checking clients"?

"An error occurred while checking clients"?
results = self._servers.get_servers()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Servers is empty!")
def _check_users(self):
self._logger.debug(__name__, f"Start checking Users table")
for g in self._bot.guilds:
g: discord.Guild = g
try:
server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
for u in g.members:
u: Union[discord.Member, discord.User] = u
if u.bot:
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
if user is not None:
continue
self._logger.warn(__name__, f"User not found in database: {u.id}")
self._logger.debug(__name__, f"Add user: {u.id}")
self._users.add_user(User(u.id, 0, server))
self._db_context.save_changes()
Review

An anderen Stellen wird geprüft, ob der Eintrag auch wirklich gespeichert wurde.

user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)

if user is None:
    self._logger.fatal(__name__, f"Cannot add user: {u.id}")
    continue 
    
self._logger.debug(__name__, f"Added user: {u.id}")
An anderen Stellen wird geprüft, ob der Eintrag auch wirklich gespeichert wurde. ```python user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id) if user is None: self._logger.fatal(__name__, f"Cannot add user: {u.id}") continue self._logger.debug(__name__, f"Added user: {u.id}") ```
self._logger.debug(__name__, f"Added User: {u.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get User", e)
Review

"An error occurred while checking users"?

"An error occurred while checking users"?
results = self._users.get_users()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Users is empty!")
def _check_user_joins(self):
self._logger.debug(__name__, f"Start checking UserJoinedServers table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
Ebola-Chan marked this conversation as resolved
Review

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn server None ist.
Evtl nach Protokollieren ein continue?

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn ```server``` None ist. Evtl nach Protokollieren ein ```continue```?
try:
for u in guild.members:
u: discord.User = u
if u.bot:
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
Ebola-Chan marked this conversation as resolved
Review

Hier sollte es zu einer NullReferenceException kommen, wenn server None ist.

Hier sollte es zu einer NullReferenceException kommen, wenn ```server``` None ist.
if user is None:
self._logger.fatal(__name__, f"User not found in database: {u.id}")
Ebola-Chan marked this conversation as resolved
Review

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn user None ist. Evtl nach Protokollieren ein continue?

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn ```user``` None ist. Evtl nach Protokollieren ein ```continue```?
join = self._user_joins.find_active_user_joined_server_by_user_id(user.id)
Ebola-Chan marked this conversation as resolved
Review

Hier sollte es zu einer NullReferenceException kommen, wenn user None ist.

Hier sollte es zu einer NullReferenceException kommen, wenn ```user``` None ist.
if join is not None:
continue
m: discord.Member = u
self._logger.warn(
__name__,
f"Active UserJoinedServer not found in database: {guild.id}:{u.id}@{m.joined_at}",
)
self._logger.debug(
__name__,
f"Add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}",
)
self._user_joins.add_user_joined_server(
UserJoinedServer(user, self._dtp.transform(m.joined_at), None)
)
self._db_context.save_changes()
Review

An anderen Stellen wird geprüft, ob der Eintrag auch wirklich gespeichert wurde.

join = self._user_joins.find_active_user_joined_server_by_user_id(user.id)

if join is None:
    self._logger.fatal(__name__, f"Cannot add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}")
    continue 
    
self._logger.debug(__name__, f"Added UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}")
An anderen Stellen wird geprüft, ob der Eintrag auch wirklich gespeichert wurde. ```python join = self._user_joins.find_active_user_joined_server_by_user_id(user.id) if join is None: self._logger.fatal(__name__, f"Cannot add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}") continue self._logger.debug(__name__, f"Added UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}") ```
self._logger.debug(__name__, f"Added UserJoinedServer: {u.id}")
Review

Im Obrigen Beispiel hatte ich die Meldung angepasst.
"Added UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}"

Im Obrigen Beispiel hatte ich die Meldung angepasst. ```"Added UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}"```
except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedServer", e)
Review

"An error occurred while checking UserJoinedServers"?

"An error occurred while checking UserJoinedServers"?
results = self._users.get_users()
Review

Den Block

	        results = self._users.get_users()
            if results is None or len(results) == 0:
                self._logger.error(__name__, f"Table Users is empty!")

            joins = self._user_joins.get_user_joined_servers()
            for join in joins:
                join: UserJoinedServer = join
                if join.user.server.discord_id != guild.id:
                    continue

                if join.leaved_on is not None:
                    continue

                dc_user = guild.get_member(join.user.discord_id)
                if dc_user is None:
                    self._logger.warn(
                        __name__,
                        f"User {join.user.discord_id} already left the server.",
                    )
                    join.leaved_on = datetime.now()
                    self._user_joins.update_user_joined_server(join)

            self._db_context.save_changes()

hast du außerhalb vom try except. Bei allen anderen Methoden sind die Befehle innerhalb des tyr except

Den Block ```python results = self._users.get_users() if results is None or len(results) == 0: self._logger.error(__name__, f"Table Users is empty!") joins = self._user_joins.get_user_joined_servers() for join in joins: join: UserJoinedServer = join if join.user.server.discord_id != guild.id: continue if join.leaved_on is not None: continue dc_user = guild.get_member(join.user.discord_id) if dc_user is None: self._logger.warn( __name__, f"User {join.user.discord_id} already left the server.", ) join.leaved_on = datetime.now() self._user_joins.update_user_joined_server(join) self._db_context.save_changes() ``` hast du außerhalb vom ```try except```. Bei allen anderen Methoden sind die Befehle innerhalb des ```tyr except```
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Users is empty!")
joins = self._user_joins.get_user_joined_servers()
for join in joins:
join: UserJoinedServer = join
if join.user.server.discord_id != guild.id:
continue
if join.leaved_on is not None:
continue
dc_user = guild.get_member(join.user.discord_id)
if dc_user is None:
self._logger.warn(
__name__,
f"User {join.user.discord_id} already left the server.",
)
join.leaved_on = datetime.now()
self._user_joins.update_user_joined_server(join)
self._db_context.save_changes()
def _check_user_joins_vc(self):
self._logger.debug(__name__, f"Start checking UserJoinedVoiceChannel table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
server = self._servers.find_server_by_discord_id(guild.id)
Ebola-Chan marked this conversation as resolved
Review

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn server None ist.
Evtl nach Protokollieren ein continue?

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn ```server``` None ist. Evtl nach Protokollieren ein ```continue```?
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
try:
# close open voice states
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
Ebola-Chan marked this conversation as resolved
Review

Hier sollte es zu einer NullReferenceException kommen, wenn server None ist.

Hier sollte es zu einer NullReferenceException kommen, wenn ```server``` None ist.
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
Ebola-Chan marked this conversation as resolved
Review

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn user None ist. Evtl nach Protokollieren ein continue?

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn ```user``` None ist. Evtl nach Protokollieren ein ```continue```?
joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.id)
Ebola-Chan marked this conversation as resolved
Review

Hier sollte es zu einer NullReferenceException kommen, wenn user None ist.

Hier sollte es zu einer NullReferenceException kommen, wenn ```user``` None ist.
if joins is None or len(joins) == 0:
continue
for join in joins:
self._logger.warn(
__name__,
f"Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}",
)
join.leaved_on = datetime.now()
if (
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
) > settings.max_voice_state_hours:
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
self._user_joins_vc.update_user_joined_voice_channel(join)
if self._is_for_shutdown:
user.xp = round(join.time * settings.xp_per_ontime_hour)
self._users.update_user(user)
self._db_context.save_changes()
if self._is_for_shutdown:
return
# add open voice states
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
if member.voice is None or member.voice.channel.id in settings.afk_channel_ids:
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
Ebola-Chan marked this conversation as resolved
Review

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn user None ist. Evtl nach Protokollieren ein continue?

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn ```user``` None ist. Evtl nach Protokollieren ein ```continue```?
join = UserJoinedVoiceChannel(user, member.voice.channel.id, datetime.now())
Ebola-Chan marked this conversation as resolved
Review

Hier sollte es zu einer NullReferenceException kommen, wenn user None ist.

Hier sollte es zu einer NullReferenceException kommen, wenn ```user``` None ist.
self._user_joins_vc.add_user_joined_voice_channel(join)
self._db_context.save_changes()
except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedVoiceChannel", e)
Review

"An error occurred while checking user joins"?

"An error occurred while checking user joins"?
def _check_user_joined_gs(self):
self._logger.debug(__name__, f"Start checking UserJoinedGameServer table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
Ebola-Chan marked this conversation as resolved
Review

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn server None ist.
Evtl nach Protokollieren ein continue?

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn ```server``` None ist. Evtl nach Protokollieren ein ```continue```?
try:
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
Ebola-Chan marked this conversation as resolved
Review

Hier sollte es zu einer NullReferenceException kommen, wenn server None ist.

Hier sollte es zu einer NullReferenceException kommen, wenn ```server``` None ist.
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
Ebola-Chan marked this conversation as resolved
Review

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn user None ist. Evtl nach Protokollieren ein continue?

Wie unten Angemerkt kommt es zu einer NullReferenceException wenn ```user``` None ist. Evtl nach Protokollieren ein ```continue```?
joins = self._user_joined_gs.find_active_user_joined_game_servers_by_user_id(user.id)
Ebola-Chan marked this conversation as resolved
Review

Hier sollte es zu einer NullReferenceException kommen, wenn user None ist.

Hier sollte es zu einer NullReferenceException kommen, wenn ```user``` None ist.
if joins is None or len(joins) == 0:
continue
for join in joins:
self._logger.warn(
__name__,
f"Active UserJoinedGameServer found in database: {guild.id}:{member.id}@{join.joined_on}",
)
join.leaved_on = datetime.now()
settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
if (
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
) > settings.max_voice_state_hours:
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
self._user_joined_gs.update_user_joined_game_server(join)
if self._is_for_shutdown:
user.xp = round(join.time * settings.xp_per_ontime_hour)
self._users.update_user(user)
self._db_context.save_changes()
except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
Review

"An error occurred while checking UserJoinedGameServer"?

"An error occurred while checking UserJoinedGameServer"?
def check_data_integrity(self, is_for_shutdown=False):
if is_for_shutdown != self._is_for_shutdown:
self._is_for_shutdown = is_for_shutdown
self._check_known_users()
self._check_servers()
self._check_clients()
self._check_users()
self._check_user_joins()
self._check_user_joins_vc()
self._check_user_joined_gs()

View File

@ -1,31 +1,11 @@
from ctypes import Union
from datetime import datetime, timedelta
from datetime import datetime
import discord
from cpl_core.configuration import ConfigurationABC
from cpl_core.database.context import DatabaseContextABC
from cpl_discord.events import OnReadyABC
from cpl_discord.service import DiscordBotServiceABC
from bot_core.logging.database_logger import DatabaseLogger
from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe
from bot_data.abc.client_repository_abc import ClientRepositoryABC
from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC
from bot_data.abc.user_joined_game_server_repository_abc import UserJoinedGameServerRepositoryABC
from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC
from bot_data.abc.user_joined_voice_channel_repository_abc import (
UserJoinedVoiceChannelRepositoryABC,
)
from bot_data.abc.user_repository_abc import UserRepositoryABC
from bot_data.model.client import Client
from bot_data.model.known_user import KnownUser
from bot_data.model.server import Server
from bot_data.model.user import User
from bot_data.model.user_joined_server import UserJoinedServer
from bot_data.model.user_joined_voice_channel import UserJoinedVoiceChannel
from bot_core.service.data_integrity_service import DataIntegrityService
from bot_data.service.seeder_service import SeederService
from bot_data.service.user_repository_service import ServerRepositoryABC
from modules.base.configuration.base_server_settings import BaseServerSettings
class DatabaseOnReadyEvent(OnReadyABC):
@ -34,31 +14,13 @@ class DatabaseOnReadyEvent(OnReadyABC):
config: ConfigurationABC,
logger: DatabaseLogger,
seeder: SeederService,
bot: DiscordBotServiceABC,
db_context: DatabaseContextABC,
server_repo: ServerRepositoryABC,
user_repo: UserRepositoryABC,
client_repo: ClientRepositoryABC,
known_users: KnownUserRepositoryABC,
user_joins: UserJoinedServerRepositoryABC,
user_joins_vc: UserJoinedVoiceChannelRepositoryABC,
user_joined_gs: UserJoinedGameServerRepositoryABC,
dtp: DateTimeOffsetPipe,
data_integrity: DataIntegrityService,
):
self._config = config
self._logger = logger
self._seeder = seeder
self._bot = bot
self._db_context = db_context
self._servers = server_repo
self._users = user_repo
self._clients = client_repo
self._known_users = known_users
self._user_joins = user_joins
self._user_joins_vc = user_joins_vc
self._user_joined_gs = user_joined_gs
self._dtp = dtp
self._data_integrity = data_integrity
OnReadyABC.__init__(self)
self._logger.info(__name__, f"Module {type(self)} loaded")
@ -83,306 +45,10 @@ class DatabaseOnReadyEvent(OnReadyABC):
self._logger.error(__name__, "Database init time calculation failed", e)
return
def _check_known_users(self):
self._logger.debug(__name__, f"Start checking KnownUsers table, {len(self._bot.users)}")
for u in self._bot.users:
u: discord.User = u
try:
if u.bot:
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._known_users.find_user_by_discord_id(u.id)
if user is not None:
continue
self._logger.warn(__name__, f"Unknown user: {u.id}")
self._logger.debug(__name__, f"Add user: {u.id}")
self._known_users.add_user(KnownUser(u.id))
self._db_context.save_changes()
user = self._known_users.find_user_by_discord_id(u.id)
if user is None:
self._logger.fatal(__name__, f"Cannot add user: {u.id}")
self._logger.debug(__name__, f"Added user: {u.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get user", e)
def _check_servers(self):
self._logger.debug(__name__, f"Start checking Servers table")
for g in self._bot.guilds:
g: discord.Guild = g
try:
server = self._servers.find_server_by_discord_id(g.id)
if server is not None:
continue
self._logger.warn(__name__, f"Server not found in database: {g.id}")
self._logger.debug(__name__, f"Add server: {g.id}")
self._servers.add_server(Server(g.id))
self._db_context.save_changes()
server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Cannot add server: {g.id}")
self._logger.debug(__name__, f"Added server: {g.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get server", e)
results = self._servers.get_servers()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Servers is empty!")
def _check_clients(self):
self._logger.debug(__name__, f"Start checking Clients table")
for g in self._bot.guilds:
g: discord.Guild = g
try:
server: Server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
client = self._clients.find_client_by_server_id(server.id)
if client is not None:
continue
self._logger.warn(
__name__,
f"Client for server {g.id} not found in database: {self._bot.user.id}",
)
self._logger.debug(__name__, f"Add client: {self._bot.user.id}")
self._clients.add_client(Client(self._bot.user.id, 0, 0, 0, 0, 0, server))
self._db_context.save_changes()
client = self._clients.find_client_by_server_id(server.id)
if client is None:
self._logger.fatal(
__name__,
f"Cannot add client {self._bot.user.id} for server {g.id}",
)
self._logger.debug(__name__, f"Added client: {g.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get client", e)
results = self._servers.get_servers()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Servers is empty!")
def _check_users(self):
self._logger.debug(__name__, f"Start checking Users table")
for g in self._bot.guilds:
g: discord.Guild = g
try:
server = self._servers.find_server_by_discord_id(g.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {g.id}")
for u in g.members:
u: Union[discord.Member, discord.User] = u
if u.bot:
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
if user is not None:
continue
self._logger.warn(__name__, f"User not found in database: {u.id}")
self._logger.debug(__name__, f"Add user: {u.id}")
self._users.add_user(User(u.id, 0, server))
self._db_context.save_changes()
self._logger.debug(__name__, f"Added User: {u.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get User", e)
results = self._users.get_users()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Users is empty!")
def _check_user_joins(self):
self._logger.debug(__name__, f"Start checking UserJoinedServers table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
try:
for u in guild.members:
u: discord.User = u
if u.bot:
self._logger.trace(__name__, f"User {u.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(u.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {u.id}")
join = self._user_joins.find_active_user_joined_server_by_user_id(user.id)
if join is not None:
continue
m: discord.Member = u
self._logger.warn(
__name__,
f"Active UserJoinedServer not found in database: {guild.id}:{u.id}@{m.joined_at}",
)
self._logger.debug(
__name__,
f"Add UserJoinedServer: {guild.id}:{u.id}@{m.joined_at}",
)
self._user_joins.add_user_joined_server(
UserJoinedServer(user, self._dtp.transform(m.joined_at), None)
)
self._db_context.save_changes()
self._logger.debug(__name__, f"Added UserJoinedServer: {u.id}")
except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedServer", e)
results = self._users.get_users()
if results is None or len(results) == 0:
self._logger.error(__name__, f"Table Users is empty!")
joins = self._user_joins.get_user_joined_servers()
for join in joins:
join: UserJoinedServer = join
if join.user.server.discord_id != guild.id:
continue
if join.leaved_on is not None:
continue
dc_user = guild.get_member(join.user.discord_id)
if dc_user is None:
self._logger.warn(
__name__,
f"User {join.user.discord_id} already left the server.",
)
join.leaved_on = datetime.now()
self._user_joins.update_user_joined_server(join)
self._db_context.save_changes()
def _check_user_joins_vc(self):
self._logger.debug(__name__, f"Start checking UserJoinedVoiceChannel table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
try:
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.id)
if joins is None or len(joins) == 0:
continue
for join in joins:
self._logger.warn(
__name__,
f"Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}",
)
join.leaved_on = datetime.now()
if (
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
) > settings.max_voice_state_hours:
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
self._user_joins_vc.update_user_joined_voice_channel(join)
# todo: maybe add XP
self._db_context.save_changes()
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
if member.voice is None or member.voice.channel.id in settings.afk_channel_ids:
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
join = UserJoinedVoiceChannel(user, member.voice.channel.id, datetime.now())
self._user_joins_vc.add_user_joined_voice_channel(join)
self._db_context.save_changes()
self._logger.warn(__name__, f"VS {member.voice}")
except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedVoiceChannel", e)
def _check_user_joined_gs(self):
self._logger.debug(__name__, f"Start checking UserJoinedGameServer table")
for guild in self._bot.guilds:
guild: discord.Guild = guild
server = self._servers.find_server_by_discord_id(guild.id)
if server is None:
self._logger.fatal(__name__, f"Server not found in database: {guild.id}")
try:
for member in guild.members:
if member.bot:
self._logger.trace(__name__, f"User {member.id} is ignored, because its a bot")
continue
user = self._users.find_user_by_discord_id_and_server_id(member.id, server.id)
if user is None:
self._logger.fatal(__name__, f"User not found in database: {member.id}")
joins = self._user_joined_gs.find_active_user_joined_game_servers_by_user_id(user.id)
if joins is None or len(joins) == 0:
continue
for join in joins:
self._logger.warn(
__name__,
f"Active UserJoinedGameServer found in database: {guild.id}:{member.id}@{join.joined_on}",
)
join.leaved_on = datetime.now()
settings: BaseServerSettings = self._config.get_configuration(f"BaseServerSettings_{guild.id}")
if (
(join.leaved_on - join.joined_on).total_seconds() / 60 / 60
) > settings.max_voice_state_hours:
join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours)
self._user_joined_gs.update_user_joined_game_server(join)
# todo: maybe add XP
self._db_context.save_changes()
except Exception as e:
self._logger.error(__name__, f"Cannot get UserJoinedGameServer", e)
async def on_ready(self):
self._logger.debug(__name__, f"Module {type(self)} started")
self._check_known_users()
self._check_servers()
self._check_clients()
self._check_users()
self._check_user_joins()
self._check_user_joins_vc()
self._check_user_joined_gs()
self._data_integrity.check_data_integrity()
await self._seeder.seed()
self._validate_init_time()