python ircd using asyncio
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

60 lines
2.2 KiB

  1. from dataclasses import dataclass, field
  2. from datetime import datetime
  3. from typing import Dict, Optional
  4. from paircd.client import Client
  5. from paircd.channel import Channel
  6. from paircd.reply import QUIT
  7. @dataclass
  8. class Server:
  9. clients_by_nick: Dict[str, Client] = field(default_factory=dict)
  10. channels_by_name: Dict[str, Channel] = field(default_factory=dict)
  11. create_time: datetime = field(default_factory=datetime.utcnow)
  12. def add_client(self, client: Client) -> None:
  13. self.clients_by_nick[client.nickname] = client
  14. def get_channel_by_name(self, name: str, create: bool = True) -> Optional[Channel]:
  15. if name not in self.channels_by_name and create:
  16. self.channels_by_name[name] = Channel(name=name)
  17. return self.channels_by_name.get(name)
  18. def get_client_by_name(self, name: str) -> Optional[Client]:
  19. return self.clients_by_nick.get(name)
  20. def remove_client_by_name(self, name: str) -> None:
  21. del self.clients_by_nick[name]
  22. def rename_client(self, name: str, new_name: str) -> None:
  23. if name not in self.clients_by_nick:
  24. raise KeyError(f"No client on server with nick {name}")
  25. if new_name in self.clients_by_nick:
  26. raise KeyError(f"Client already exists with nick {new_name}")
  27. self.clients_by_nick[new_name] = self.clients_by_nick[name]
  28. del self.clients_by_nick[name]
  29. async def disconnect_client(self, nick: str, quit_msg: str) -> None:
  30. client = self.clients_by_nick[nick]
  31. if client.closed:
  32. return
  33. client.log(f"is quitting: {quit_msg}")
  34. msg = QUIT(quit_msg, prefix=client.id())
  35. for client in self.clients_by_nick.values():
  36. if client.nickname == nick:
  37. continue
  38. client.write_message(msg)
  39. for channel_name in client.channels:
  40. channel = self.get_channel_by_name(channel_name, create=False)
  41. if channel is None:
  42. continue
  43. channel.remove_client_by_nick(client.nickname)
  44. if channel.get_channel_size() == 0:
  45. del self.channels_by_name[channel_name]
  46. self.remove_client_by_name(client.nickname)
  47. await client.close()