43918066a9
fix for !whois <char_id> added logging for invalid ORG_MSG_EVENT's
166 lines
6.1 KiB
Python
166 lines
6.1 KiB
Python
from core.aochat import client_packets
|
|
from core.aochat import server_packets
|
|
from core.conn import Conn
|
|
from core.decorators import instance
|
|
from core.logger import Logger
|
|
from core.lookup.character_service import CharacterService
|
|
|
|
|
|
@instance()
|
|
class BuddyService:
|
|
BUDDY_LOGON_EVENT = "buddy_logon"
|
|
BUDDY_LOGOFF_EVENT = "buddy_logoff"
|
|
|
|
def __init__(self):
|
|
self.buddy_list = {}
|
|
self.buddy_list_size = 0
|
|
self.logger = Logger(__name__)
|
|
|
|
def inject(self, registry):
|
|
self.character_service: CharacterService = registry.get_instance("character_service")
|
|
self.bot = registry.get_instance("bot")
|
|
self.event_service = registry.get_instance("event_service")
|
|
|
|
def pre_start(self):
|
|
self.bot.register_packet_handler(server_packets.BuddyAdded.id, self.handle_add)
|
|
self.bot.register_packet_handler(server_packets.BuddyRemoved.id, self.handle_remove)
|
|
self.bot.register_packet_handler(server_packets.LoginOK.id, self.handle_login_ok)
|
|
self.event_service.register_event_type(self.BUDDY_LOGON_EVENT)
|
|
self.event_service.register_event_type(self.BUDDY_LOGOFF_EVENT)
|
|
|
|
def handle_add(self, conn: Conn, packet):
|
|
buddy = self.buddy_list[conn.id].get(packet.char_id, {"types": [], "conn_id": conn.id})
|
|
buddy["online"] = packet.online
|
|
self.buddy_list[conn.id][packet.char_id] = buddy
|
|
|
|
# verify that buddy does not exist on any other conn
|
|
for conn_id, conn_buddy_list in self.buddy_list.items():
|
|
if conn.id != conn_id:
|
|
if buddy := conn_buddy_list.get(packet.char_id, None):
|
|
if buddy["online"] is None:
|
|
# remove from other conn list
|
|
del conn_buddy_list[packet.char_id]
|
|
else:
|
|
# remove from this conn
|
|
self.logger.warning(f"Removing char '{packet.char_id}' from conn '{conn.id}' "
|
|
f"since it already exists on another conn")
|
|
conn.send_packet(client_packets.BuddyRemove(packet.char_id))
|
|
|
|
if packet.online == 1:
|
|
self.event_service.fire_event(self.BUDDY_LOGON_EVENT, packet)
|
|
else:
|
|
self.event_service.fire_event(self.BUDDY_LOGOFF_EVENT, packet)
|
|
|
|
def handle_remove(self, conn: Conn, packet):
|
|
conn_buddy_list = self.buddy_list[conn.id]
|
|
if packet.char_id in conn_buddy_list:
|
|
if len(conn_buddy_list[packet.char_id]["types"]) > 0:
|
|
self.logger.warning(f"Removing buddy {packet.char_id} that still has "
|
|
f"types {conn_buddy_list[packet.char_id]['types']}")
|
|
|
|
del conn_buddy_list[packet.char_id]
|
|
|
|
def handle_login_ok(self, conn: Conn, _):
|
|
self.buddy_list_size += 1000
|
|
self.buddy_list[conn.id] = {}
|
|
self.buddy_list[conn.id][conn.char_id] = {"online": True, "types": [], "conn_id": conn.id}
|
|
|
|
def add_buddy(self, char_id, _type):
|
|
if not char_id:
|
|
return False
|
|
|
|
# check if we are trying to add a conn as a buddy
|
|
if self.is_conn_char_id(char_id):
|
|
return False
|
|
|
|
buddy = self.get_buddy(char_id)
|
|
if buddy:
|
|
buddy["types"].append(_type)
|
|
else:
|
|
conn = self.get_conn_for_new_buddy()
|
|
if conn.char_id != char_id:
|
|
conn.send_packet(client_packets.BuddyAdd(char_id, "\1"))
|
|
self.buddy_list[conn.id][char_id] = {"online": None, "types": [_type], "conn_id": conn.id}
|
|
|
|
return True
|
|
|
|
def is_conn_char_id(self, char_id):
|
|
for _id, conn in self.bot.conns.items():
|
|
if conn.char_id == char_id:
|
|
return True
|
|
|
|
return False
|
|
|
|
def remove_buddy(self, char_id, _type, force_remove=False):
|
|
if char_id:
|
|
buddy = self.get_buddy(char_id)
|
|
if not buddy:
|
|
return False
|
|
|
|
if _type in buddy["types"]:
|
|
buddy["types"].remove(_type)
|
|
|
|
if len(buddy["types"]) == 0 or force_remove:
|
|
if not self.is_conn_char_id(char_id):
|
|
conn = self.bot.conns[buddy["conn_id"]]
|
|
conn.send_packet(client_packets.BuddyRemove(char_id))
|
|
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def remove_buddy_type(self, chars: [], _type: str, force_remove=False):
|
|
removed = 0
|
|
if len(chars) < 1:
|
|
return removed
|
|
for bot, buddylist in self.buddy_list.items():
|
|
for x in buddylist.keys():
|
|
if x not in chars:
|
|
continue
|
|
if _type not in buddylist[x]['types']:
|
|
continue
|
|
buddylist[x]["types"].remove(_type)
|
|
if len(buddylist[x]["types"]) == 0 or force_remove:
|
|
conn = self.bot.conns[buddylist[x]["conn_id"]]
|
|
conn.send_packet(client_packets.BuddyRemove(x))
|
|
removed += 1
|
|
return removed
|
|
|
|
def get_buddy(self, char_id):
|
|
for conn_id, conn_buddy_list in self.buddy_list.items():
|
|
if char_id in conn_buddy_list:
|
|
return conn_buddy_list[char_id]
|
|
return None
|
|
|
|
def is_online(self, char_id):
|
|
buddy = self.get_buddy(char_id)
|
|
if buddy is None:
|
|
return None
|
|
else:
|
|
return buddy.get("online", None)
|
|
|
|
def get_all_buddies(self):
|
|
result = {}
|
|
for conn_id, conn_buddy_list in self.buddy_list.items():
|
|
for char_id, buddy in conn_buddy_list.items():
|
|
result[char_id] = buddy
|
|
|
|
return result
|
|
|
|
def get_buddy_list_size(self):
|
|
count = 0
|
|
for conn_id, conn_buddy_list in self.buddy_list.items():
|
|
count += len(conn_buddy_list)
|
|
|
|
return count
|
|
|
|
def get_conn_for_new_buddy(self):
|
|
buddy_list_size = None
|
|
_id = None
|
|
for conn_id, conn_buddy_list in self.buddy_list.items():
|
|
if buddy_list_size is None or len(conn_buddy_list) < buddy_list_size:
|
|
buddy_list_size = len(conn_buddy_list)
|
|
_id = conn_id
|
|
|
|
return self.bot.conns.get(_id, None)
|