Browse Source

Command fixes

master
Forest Belton 3 years ago
parent
commit
bf10934c57
8 changed files with 33 additions and 21 deletions
  1. +6
    -10
      paircd/channel.py
  2. +15
    -1
      paircd/handler/join.py
  3. +2
    -2
      paircd/handler/mode.py
  4. +1
    -1
      paircd/handler/who.py
  5. +4
    -3
      paircd/handlers.py
  6. +1
    -1
      paircd/message.py
  7. +4
    -1
      paircd/reply.py
  8. +0
    -2
      paircd/server.py

+ 6
- 10
paircd/channel.py View File

@ -9,6 +9,7 @@ from paircd.message import Message
@dataclass @dataclass
class Channel: class Channel:
name: str name: str
topic: str = ""
clients_by_nick: Dict[str, Client] = field(default_factory=dict) clients_by_nick: Dict[str, Client] = field(default_factory=dict)
msg_queue: Queue = field(default_factory=Queue) msg_queue: Queue = field(default_factory=Queue)
@ -18,17 +19,12 @@ class Channel:
def remove_client_by_nick(self, nick: str) -> None: def remove_client_by_nick(self, nick: str) -> None:
del self.clients_by_nick[nick] del self.clients_by_nick[nick]
async def process(self) -> None:
while True:
msg = await self.msg_queue.get()
for client in self.clients_by_nick.values():
# Don't broadcast client's messages back to themselves
if msg.cmd == "PRIVMSG" and msg.prefix == client.id():
continue
client.write_message(msg)
def write_message(self, msg: Message) -> None: def write_message(self, msg: Message) -> None:
self.msg_queue.put_nowait(msg)
for client in self.clients_by_nick.values():
# Don't broadcast client's messages back to themselves
if msg.cmd == "PRIVMSG" and msg.prefix == client.id():
continue
client.write_message(msg)
def get_modes(self) -> List[str]: def get_modes(self) -> List[str]:
return [] return []

+ 15
- 1
paircd/handler/join.py View File

@ -1,4 +1,5 @@
import logging import logging
from paircd.reply import RPL_ENDOFNAMES, RPL_NAMREPLY, RPL_TOPIC
from paircd.client import Client from paircd.client import Client
from paircd.command_handler import CommandHandler from paircd.command_handler import CommandHandler
@ -26,6 +27,19 @@ class JoinHandler(CommandHandler):
client.channels.add(channel_name) client.channels.add(channel_name)
client.log(f"joined {channel_name}") client.log(f"joined {channel_name}")
await channel.msg_queue.put(
channel.write_message(
Message(cmd="JOIN", args=[channel_name], prefix=client.id()) Message(cmd="JOIN", args=[channel_name], prefix=client.id())
) )
if channel.topic != "":
client.write_message(
RPL_TOPIC(client.nickname, channel_name, channel.topic)
)
client.log("TODO: implement user channel modes", level=logging.WARN)
channel_members = list(channel.clients_by_nick.keys())
client.write_message(
# "=" means public channel (ref: https://modern.ircdocs.horse/#rplnamreply-353)
RPL_NAMREPLY(client.nickname, "=", channel_name, " ".join(channel_members))
)
client.write_message(RPL_ENDOFNAMES(client.nickname, channel_name))

+ 2
- 2
paircd/handler/mode.py View File

@ -23,5 +23,5 @@ class ModeHandler(CommandHandler):
modes = f"+{modes}" modes = f"+{modes}"
client.log("TODO: implement channel modes", level=logging.WARN) client.log("TODO: implement channel modes", level=logging.WARN)
msg = RPL_CHANNELMODEIS(client.nickname, name, modes, "")
client.write_message(msg)
client.write_message(Message("MODE", args=[name, modes]))
client.write_message(RPL_CHANNELMODEIS(client.nickname, name, modes, ""))

+ 1
- 1
paircd/handler/who.py View File

@ -34,7 +34,7 @@ class WhoHandler(CommandHandler):
channel_name, channel_name,
member.username, member.username,
member.hostname, member.hostname,
"0", # server
"localhost", # server
member.nickname, member.nickname,
# TODO: Implement # TODO: Implement
"H", # H = here, G = gone "H", # H = here, G = gone

+ 4
- 3
paircd/handlers.py View File

@ -32,11 +32,12 @@ def register_cmd_handlers() -> None:
async def handle_cmd(server: Server, client: Client, msg: Message) -> None: async def handle_cmd(server: Server, client: Client, msg: Message) -> None:
if msg.cmd not in CMD_HANDLERS:
client.log(f"used unknown command {msg.cmd}", level=WARN)
cmd = msg.cmd.upper()
if cmd not in CMD_HANDLERS:
client.log(f"used unknown command {cmd}", level=WARN)
return return
handler = CMD_HANDLERS[msg.cmd]
handler = CMD_HANDLERS[cmd]
if handler.argc is not None and handler.argc != len(msg.args): if handler.argc is not None and handler.argc != len(msg.args):
client.log( client.log(
"got {len(msg.args)} arguments for {msg.cmd}, expected {handler.argc}", "got {len(msg.args)} arguments for {msg.cmd}, expected {handler.argc}",

+ 1
- 1
paircd/message.py View File

@ -22,7 +22,7 @@ class ParsingError(Exception):
class Message: class Message:
cmd: str cmd: str
args: List[str] args: List[str]
prefix: str = ""
prefix: str = "localhost"
def encode(self) -> bytes: def encode(self) -> bytes:
prefix = self.prefix prefix = self.prefix

+ 4
- 1
paircd/reply.py View File

@ -20,4 +20,7 @@ RPL_WHOISUSER = reply_fn(311, "{0} {1} {2} * :{3}")
RPL_ENDOFWHO = reply_fn(315, "{0} :End of /WHO list") RPL_ENDOFWHO = reply_fn(315, "{0} :End of /WHO list")
RPL_ENDOFWHOIS = reply_fn(318, "{0} :End of /WHOIS list") RPL_ENDOFWHOIS = reply_fn(318, "{0} :End of /WHOIS list")
RPL_CHANNELMODEIS = reply_fn(324, "{0} {1}{2}") RPL_CHANNELMODEIS = reply_fn(324, "{0} {1}{2}")
RPL_WHOREPLY = reply_fn(352, "{0} {1} {2} {3} {4} {5} :{6} {7}")
RPL_TOPIC = reply_fn(332, "{0} :{1}")
RPL_WHOREPLY = reply_fn(352, "{0} ~{1} {2} {3} {4} {5} :{6} {7}")
RPL_NAMREPLY = reply_fn(353, "{0} {1} :{2}")
RPL_ENDOFNAMES = reply_fn(366, "{0} :End of /NAMES list")

+ 0
- 2
paircd/server.py View File

@ -1,4 +1,3 @@
from asyncio import create_task
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Dict from typing import Dict
@ -17,7 +16,6 @@ class Server:
def get_channel_by_name(self, name: str) -> Channel: def get_channel_by_name(self, name: str) -> Channel:
if name not in self.channels_by_name: if name not in self.channels_by_name:
self.channels_by_name[name] = Channel(name=name) self.channels_by_name[name] = Channel(name=name)
create_task(self.channels_by_name[name].process())
return self.channels_by_name[name] return self.channels_by_name[name]
def remove_client_by_name(self, name: str) -> None: def remove_client_by_name(self, name: str) -> None:

Loading…
Cancel
Save