Added the option to !opt-in/opt-out [onlinebot only]

Fixed command & event threading
Events are now threaded by event_type (i.e. all buddy_logon events get ran in the same one)
Added default preferences
Fixed recipe loading for multiple installs (i.e. on different machines)
This commit is contained in:
2021-08-27 13:58:47 +02:00
parent d0c8c1744c
commit c04f76c0db
24 changed files with 258 additions and 122 deletions
+2 -2
View File
@@ -41,10 +41,10 @@ class Bot:
# read character list
character_list_packet: LoginCharacterList = self.read_packet()
if isinstance(character_list_packet, LoginError):
self.logger.error("Error logging in: %s" % character_list_packet.message)
self.logger.error(f"Error logging in: {character_list_packet.message}")
return False
if character not in character_list_packet.names:
self.logger.error("Character '%s' does not exist on this account" % character)
self.logger.error(f"Character '{character}' does not exist on this account")
return False
index = character_list_packet.names.index(character)
+3 -3
View File
@@ -1,9 +1,9 @@
class ChatBlob:
def __init__(self, title, msg):
def __init__(self, title, msg, prefix="", suffix=""):
self.title = title
self.msg = msg.strip("\n")
self.page_prefix = ""
self.page_postfix = ""
self.page_prefix = prefix
self.page_postfix = suffix
def __str__(self):
return f"ChatBlob('{self.title}', '{self.msg}')"
+17 -16
View File
@@ -86,7 +86,7 @@ class CommandService:
al = access_levels.get(command_key, None)
if al is not None and al != access_level.lower():
print(handler)
raise Exception("Different access levels specified for forms of command '%s'" % command_key)
raise Exception(f"Different access levels specified for forms of command '{command_key}'")
access_levels[command_key] = access_level
self.register(handler, cmd_name, params, access_level, description, inst.module_name, help_text,
@@ -182,10 +182,10 @@ class CommandService:
"""
if value in self.channels:
self.logger.error("Could not register command channel '%s': command channel already registered" % value)
self.logger.error(f"Could not register command channel '{value}': command channel already registered")
return
self.logger.debug("Registering command channel '%s'" % value)
self.logger.debug(f"Registering command channel '{value}'")
self.channels[value] = label
def is_command_channel(self, channel):
@@ -228,11 +228,11 @@ class CommandService:
command_alias = self.command_alias_service.check_for_alias(command_str)
if alias_depth_count > 20:
raise Exception("Command alias infinite recursion detected for command '%s'" % message)
raise Exception(f"Command alias infinite recursion detected for command '{message}'")
cmd_configs = self.get_command_configs(command_str, channel)
access_level = self.access_service.get_access_level(char_id)
sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, "Unknown(%d)" % char_id),
sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, f"Unknown({char_id:d})"),
access_level)
if cmd_configs:
# given a list of cmd_configs that are enabled, see if one has regex that matches incoming command_str
@@ -245,7 +245,7 @@ class CommandService:
if response is not None:
reply(response)
except Exception as e:
self.logger.error("error processing command: %s" % message, e)
self.logger.error(f"error processing command: {message}", e)
self.relay_hub_service.send_message("access_denied_logger", sender,
f"[ERROR] {sender.name}: {message}",
f"[ERROR] {sender.name}: {message}")
@@ -262,16 +262,17 @@ class CommandService:
reply(self.format_help_text(command_str, help_text))
else:
# the command is known, but no help is returned, therefore user does not have access to command
if access_level['label'] != "all":
self.relay_hub_service.send_message("access_denied_logger", sender,
f"[DENIED] {sender.name}: {message}",
f"[DENIED] {sender.name}: {message}")
self.bot.send_mass_message(char_id, self.getresp("global", "access_denied"))
self.access_denied_response(message, sender, cmd_config, reply)
# if access_level['label'] != "all":
# self.relay_hub_service.send_message("access_denied_logger", sender,
# f"[DENIED] {sender.name}: {message}",
# f"[DENIED] {sender.name}: {message}")
# self.bot.send_mass_message(char_id, self.getresp("global", "access_denied"))
else:
self.handle_unknown_command(command_str, command_args, channel, sender, reply)
except Exception as e:
self.logger.error("error processing command: %s" % message, e)
sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, "Unknown(%d)" % char_id),
self.logger.error(f"error processing command: {message}", e)
sender = SenderObj(char_id, self.character_service.resolve_char_to_name(char_id, f"Unknown({char_id:d})"),
0)
self.relay_hub_service.send_message("access_denied_logger", sender, f"[ERROR] {sender.name}: {message}",
f"[ERROR] {sender.name}: {message}")
@@ -426,7 +427,7 @@ class CommandService:
False)
t: Thread = Thread(target=i, daemon=True)
t.run()
t.start()
def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage):
if not self.setting_service.get("accept_commands_from_slave_bots").get_value() and conn.id != "main":
@@ -449,7 +450,7 @@ class CommandService:
lambda msg: self.bot.send_private_channel_message(msg, private_channel_id=conn.char_id,
conn_id=conn.id),
conn,
False), daemon=True).run()
False), daemon=True).start()
def handle_public_channel_message(self, conn: Conn, packet: server_packets.PublicChannelMessage):
if not self.setting_service.get("accept_commands_from_slave_bots").get_value() and conn.id != "main":
@@ -472,7 +473,7 @@ class CommandService:
packet.char_id,
lambda msg: self.bot.send_org_message(msg, conn_id=conn.id),
conn,
False), daemon=True).run()
False), daemon=True).start()
def trim_command_symbol(self, s):
symbol = self.setting_service.get("symbol").get_value()
+3 -4
View File
@@ -75,13 +75,12 @@ class DB:
if string.__contains__("UPDATE ") or string.__contains__("INSERT "):
conn.commit()
except Exception as e:
raise SqlException("SQL Error: '%s' for '%s' [%s]" % (
str(e), sql, ", ".join(map(lambda x: str(x), params)))) from e
raise SqlException( f"SQL Error: '{str(e)}' for '{sql}' "
f"[{', '.join(map(lambda x: str(x), params))}]") from e
elapsed = time.time() - start_time
result = callback(cur)
if elapsed > 5:
self.logger.warning("slow query (%fs) '%s' for params: %s" % (elapsed, sql, str(params)))
self.logger.warning(f"slow query ({elapsed:f}s) '{sql}' for params: {str(params)}")
return result
def query_single(self, sql, params=None, extended_like=False) -> DictObject:
+19 -13
View File
@@ -72,7 +72,7 @@ class EventService:
"""
if len(inspect.signature(handler).parameters) != 2:
raise Exception(
"Incorrect number of arguments for handler '%s.%s()'" % (handler.__module__, handler.__name__))
f"Incorrect number of arguments for handler '{handler.__module__}.{handler.__name__}()'")
event_base_type, event_sub_type = self.get_event_type_parts(event_type)
module = module.lower()
@@ -80,12 +80,12 @@ class EventService:
is_hidden = 1 if is_hidden else 0
is_enabled = 1 if is_enabled else 0
if event_base_type not in self.event_types:
self.logger.error("Could not register handler '%s' for event type '%s': event type does not exist" % (
handler_name, event_type))
self.logger.error(
f"Could not register handler '{handler_name}' for event type '{event_type}': event type does not exist")
return
if not description:
self.logger.warning("No description for event_type '%s' and handler '%s'" % (event_type, handler_name))
self.logger.warning(f"No description for event_type '{event_type}' and handler '{handler_name}'")
row = self.db.query_single("SELECT 1 FROM event_config WHERE event_type = ? AND handler = ?",
[event_base_type, handler_name])
@@ -117,28 +117,34 @@ class EventService:
event_base_type, event_sub_type = self.get_event_type_parts(event_type)
if event_base_type not in self.event_types:
self.logger.error("Could not fire event type '%s': event type does not exist" % event_type)
self.logger.error(f"Could not fire event type '{event_type}': event type does not exist")
return
data = self.get_handlers(event_base_type, event_sub_type)
for row in data:
if event_type != "connect":
t = Thread(target=self.call_handler, args=(row.handler, event_type, event_data), daemon=True)
t.run()
else:
self.call_handler(row.handler, event_type, event_data)
# We dont want to spawn a new Thread for each event handler, but only per event type.
def i():
for row in data:
if event_type != "connect":
self.call_handler(row.handler, event_type, event_data)
else:
self.call_handler(row.handler, event_type, event_data)
if event_type != "connect":
Thread(target=i, daemon=True).start()
else:
i()
def call_handler(self, handler_method, event_type, event_data):
handler = self.handlers.get(handler_method, None)
if not handler:
self.logger.error(
"Could not find handler callback for event type '%s' and handler '%s'" % (event_type, handler_method))
f"Could not find handler callback for event type '{event_type}' and handler '{handler_method}'")
return
try:
handler(event_type, event_data)
except Exception as e:
self.logger.error("error processing event '%s'" % event_type, e)
self.logger.error(f"error processing event '{event_type}'", e)
def get_event_type_parts(self, event_type):
parts = event_type.lower().split(":", 1)
+4 -4
View File
@@ -41,13 +41,13 @@ class CharacterHistoryService:
# with TorRequests() as tor_request:
# with tor_request.get_session(1) as session:
# r = session.get(url, timeout=5)
r = requests.get(url, timeout=5, headers={"User-Agent": self.bot.major_version})
result = r.json()
# r = requests.get(url, timeout=5, headers={"User-Agent": self.bot.major_version})
result = json.loads(r)
except ReadTimeout:
self.logger.warning("Timeout while requesting '%s'" % url)
self.logger.warning(f"Timeout while requesting '{url}'")
result = None
except Exception as e:
self.logger.error("Error requesting history for url '%s'" % url, e)
self.logger.error(f"Error requesting history for url '{url}'", e)
result = None
if result:
+1 -1
View File
@@ -33,7 +33,7 @@ class PrivateChannelService:
self.bot.register_packet_handler(server_packets.PrivateChannelMessage.id,
self.handle_private_channel_message, priority=30)
self.access_service.register_access_level("guest", 95, self.in_private_channel)
self.access_service.register_access_level("guest", 94, self.in_private_channel)
def handle_private_channel_message(self, conn: Conn, packet: server_packets.PrivateChannelMessage):
if conn.id != "main":
+1 -1
View File
@@ -207,7 +207,7 @@ class Text:
label2 = self.format_message(label)
else:
label2 = self.format_message(label) + " (Page " + str(index) + " / " + str(num_pages) + ")"
return chatblob.page_prefix + self.format_page(label2, page) + chatblob.page_postfix
return self.format_message(chatblob.page_prefix) + self.format_page(label2, page) + self.format_message(chatblob.page_postfix)
return list(map(mapper, zip(pages, range(1, num_pages + 1))))
+1 -1
View File
@@ -42,7 +42,7 @@ class Tyrbot:
self.last_timer_event = 0
self.start_time = int(time.time())
self.major_version = "IGNCore v2.5"
self.minor_version = "1"
self.minor_version = "2"
self.incoming_queue = FifoQueue()
self.mass_message_queue = None
self.conns = DictObject()