irc_server.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. use futures::{io::WriteHalf, AsyncWriteExt};
  2. use log::{debug, info};
  3. use rand::{rngs::OsRng, RngCore};
  4. use smol::Async;
  5. use std::net::TcpStream;
  6. use darkfi::{net, Error, Result};
  7. use crate::privmsg::{PrivMsg, SeenPrivMsgIdsPtr};
  8. /*
  9. NICK fifififif
  10. USER username 0 * :Real
  11. :behemoth 001 fifififif :Hi, welcome to IRC
  12. :behemoth 002 fifififif :Your host is behemoth, running version miniircd-2.1
  13. :behemoth 003 fifififif :This server was created sometime
  14. :behemoth 004 fifififif behemoth miniircd-2.1 o o
  15. :behemoth 251 fifififif :There are 1 users and 0 services on 1 server
  16. :behemoth 422 fifififif :MOTD File is missing
  17. JOIN #dev
  18. :fifififif!username@127.0.0.1 JOIN #dev
  19. :behemoth 331 fifififif #dev :No topic is set
  20. :behemoth 353 fifififif = #dev :fifififif
  21. :behemoth 366 fifififif #dev :End of NAMES list
  22. PRIVMSG #dev hihi
  23. */
  24. pub struct IrcServerConnection {
  25. write_stream: WriteHalf<Async<TcpStream>>,
  26. seen_privmsg_ids: SeenPrivMsgIdsPtr,
  27. is_nick_init: bool,
  28. is_user_init: bool,
  29. is_registered: bool,
  30. nickname: String,
  31. _channels: Vec<String>,
  32. }
  33. impl IrcServerConnection {
  34. pub fn new(
  35. write_stream: WriteHalf<Async<TcpStream>>,
  36. seen_privmsg_ids: SeenPrivMsgIdsPtr,
  37. ) -> Self {
  38. Self {
  39. write_stream,
  40. seen_privmsg_ids,
  41. is_nick_init: false,
  42. is_user_init: false,
  43. is_registered: false,
  44. nickname: "".to_string(),
  45. _channels: vec![],
  46. }
  47. }
  48. pub async fn update(&mut self, line: String, p2p: net::P2pPtr) -> Result<()> {
  49. let mut tokens = line.split_ascii_whitespace();
  50. // Commands can begin with :garbage but we will reject clients doing that for now
  51. // to keep the protocol simple and focused.
  52. let command = tokens.next().ok_or(Error::MalformedPacket)?;
  53. debug!("Received command: {}", command);
  54. match command {
  55. "NICK" => {
  56. let nickname = tokens.next().ok_or(Error::MalformedPacket)?;
  57. self.is_nick_init = true;
  58. let old_nick = std::mem::replace(&mut self.nickname, nickname.to_string());
  59. let nick_reply = format!(":{}!darkfi@127.0.0.1 NICK {}\n", old_nick, self.nickname);
  60. self.reply(&nick_reply).await?;
  61. }
  62. "USER" => {
  63. // We can stuff any extra things like public keys in here
  64. // Ignore it for now
  65. self.is_user_init = true;
  66. }
  67. "JOIN" => {
  68. // Ignore since channels are all autojoin
  69. //let channel = tokens.next().ok_or(Error::MalformedPacket)?;
  70. //self.channels.push(channel.to_string());
  71. //let join_reply = format!(":{}!darkfi@127.0.0.1 JOIN {}\n", self.nickname,
  72. // channel); self.reply(&join_reply).await?;
  73. //self.write_stream.write_all(b":f00!f00@127.0.0.1 PRIVMSG #dev :y0\n").await?;
  74. }
  75. "PING" => {
  76. let line_clone = line.clone();
  77. let split_line: Vec<&str> = line_clone.split_whitespace().collect();
  78. if split_line.len() > 1 && split_line[0] == "PING" {
  79. let pong = format!("PONG {}\n", split_line[1]);
  80. self.reply(&pong).await?;
  81. }
  82. }
  83. "PRIVMSG" => {
  84. let channel = tokens.next().ok_or(Error::MalformedPacket)?;
  85. let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
  86. if substr_idx >= line.len() {
  87. return Err(Error::MalformedPacket)
  88. }
  89. let message = &line[substr_idx + 1..];
  90. info!("Message {}: {}", channel, message);
  91. let random_id = OsRng.next_u32();
  92. self.seen_privmsg_ids.add_seen(random_id).await;
  93. let protocol_msg = PrivMsg {
  94. id: random_id,
  95. nickname: self.nickname.clone(),
  96. channel: channel.to_string(),
  97. message: message.to_string(),
  98. };
  99. p2p.broadcast(protocol_msg).await?;
  100. }
  101. "QUIT" => {
  102. // Close the connection
  103. return Err(Error::ServiceStopped)
  104. }
  105. _ => {}
  106. }
  107. if !self.is_registered && self.is_nick_init && self.is_user_init {
  108. debug!("Initializing peer connection");
  109. let register_reply = format!(":darkfi 001 {} :Let there be dark\n", self.nickname);
  110. self.reply(&register_reply).await?;
  111. self.is_registered = true;
  112. // Auto-joins
  113. for channel in ["#dev", "#markets", "#welcome"] {
  114. let join_reply = format!(":{}!darkfi@127.0.0.1 JOIN {}\n", self.nickname, channel);
  115. self.reply(&join_reply).await?;
  116. }
  117. }
  118. Ok(())
  119. }
  120. pub async fn reply(&mut self, message: &str) -> Result<()> {
  121. self.write_stream.write_all(message.as_bytes()).await?;
  122. debug!("Sent {}", message);
  123. Ok(())
  124. }
  125. }