Skip to content

Commit

Permalink
Add channel model
Browse files Browse the repository at this point in the history
To split the room logic into more appropriate pieces
  • Loading branch information
exul committed Nov 4, 2017
1 parent c8c2feb commit f19b1bd
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 224 deletions.
73 changes: 34 additions & 39 deletions src/matrix-rocketchat/handlers/events/command_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ use api::{MatrixApi, RocketchatApi};
use config::Config;
use errors::*;
use handlers::rocketchat::{Credentials, Login};
use handlers::events::RoomHandler;
use i18n::*;
use models::{NewRocketchatServer, NewUserOnRocketchatServer, RocketchatServer, Room, UserOnRocketchatServer};
use models::{Channel, NewRocketchatServer, NewUserOnRocketchatServer, RocketchatServer, Room, UserOnRocketchatServer};

/// Handles command messages from the admin room
pub struct CommandHandler<'a> {
Expand Down Expand Up @@ -251,7 +250,8 @@ impl<'a> CommandHandler<'a> {
let mut command = message.split_whitespace().collect::<Vec<&str>>().into_iter();
let channel_name = command.by_ref().nth(1).unwrap_or_default();

let channel = match channels.iter().find(|channel| channel.name.clone().unwrap_or_default() == channel_name) {
let rocketchat_channel = match channels.iter().find(|channel| channel.name.clone().unwrap_or_default() == channel_name)
{
Some(channel) => channel,
None => {
bail_error!(
Expand All @@ -262,57 +262,59 @@ impl<'a> CommandHandler<'a> {
};

let username = rocketchat_api.current_username()?;
if !channel.usernames.iter().any(|u| u == &username) {
if !rocketchat_channel.usernames.iter().any(|u| u == &username) {
bail_error!(
ErrorKind::RocketchatJoinFirst(channel_name.to_string()),
t!(["errors", "rocketchat_join_first"]).with_vars(vec![("channel_name", channel_name.to_string())])
);
}

let room_handler =
RoomHandler::new(self.config, self.connection, self.logger, self.matrix_api, &bot_user_id, &event.user_id);
let room_id = match Room::matrix_id_from_rocketchat_channel_id(self.config, self.matrix_api, &server.id, &channel.id)? {
let channel = Channel::new(self.config, self.logger, self.matrix_api, rocketchat_channel.id.clone(), &server.id);
let room_id = match channel.matrix_id()? {
Some(room_id) => {
let room = Room::new(self.config, self.logger, self.matrix_api, room_id.clone());
room.bridge(event.user_id.clone(), channel_name.to_string())?;
room.bridge_for_user(event.user_id.clone(), channel_name.to_string())?;
room_id
}
None => room_handler.bridge_new_room(rocketchat_api, server, channel)?,
None => channel.bridge(
self.connection,
rocketchat_api.as_ref(),
Some(channel_name.to_string()),
&rocketchat_channel.usernames,
&bot_user_id,
&event.user_id,
)?,
};

let matrix_room_alias_id = Room::build_room_alias_id(self.config, &server.id, &channel.id)?;
let matrix_room_alias_id = channel.build_room_alias_id()?;
self.matrix_api.put_canonical_room_alias(room_id.clone(), Some(matrix_room_alias_id))?;

let message = t!(["admin_room", "room_successfully_bridged"]).with_vars(vec![
("channel_name", channel.name.clone().unwrap_or_else(|| channel.id.clone())),
("channel_name", rocketchat_channel.name.clone().unwrap_or_else(|| rocketchat_channel.id.clone())),
]);
self.matrix_api.send_text_message_event(event.room_id.clone(), bot_user_id.clone(), message.l(DEFAULT_LANGUAGE))?;

Ok(info!(self.logger, "Successfully bridged room {} to {}", &channel.id, &room_id))
Ok(info!(self.logger, "Successfully bridged room {} to {}", &rocketchat_channel.id, &room_id))
}

fn unbridge(&self, event: &MessageEvent, server: &RocketchatServer, message: &str) -> Result<()> {
let mut command = message.split_whitespace().collect::<Vec<&str>>().into_iter();
let channel_name = command.nth(1).unwrap_or_default().to_string();
let name = command.nth(1).unwrap_or_default().to_string();

let user_on_rocketchat_server = UserOnRocketchatServer::find(self.connection, &event.user_id, server.id.clone())?;
let rocketchat_api = RocketchatApi::new(server.rocketchat_url.clone(), self.logger.clone())?.with_credentials(
user_on_rocketchat_server.rocketchat_user_id.clone().unwrap_or_default(),
user_on_rocketchat_server.rocketchat_auth_token.clone().unwrap_or_default(),
);

let room_id = match Room::matrix_id_from_rocketchat_channel_name(
self.config,
self.matrix_api,
rocketchat_api.as_ref(),
&server.id,
channel_name.clone(),
)? {
let channel =
Channel::from_name(self.config, self.logger, self.matrix_api, name.clone(), &server.id, rocketchat_api.as_ref())?;
let room_id = match channel.matrix_id()? {
Some(room_id) => room_id,
None => {
bail_error!(
ErrorKind::UnbridgeOfNotBridgedRoom(channel_name.to_string()),
t!(["errors", "unbridge_of_not_bridged_room"]).with_vars(vec![("channel_name", channel_name)])
ErrorKind::UnbridgeOfNotBridgedRoom(name.to_string()),
t!(["errors", "unbridge_of_not_bridged_room"]).with_vars(vec![("channel_name", name)])
);
}
};
Expand All @@ -324,22 +326,21 @@ impl<'a> CommandHandler<'a> {
if !user_ids.is_empty() {
let user_ids = user_ids.iter().map(|id| id.to_string()).collect::<Vec<String>>().join(", ");
bail_error!(
ErrorKind::RoomNotEmpty(channel_name.to_string(), user_ids.clone()),
t!(["errors", "room_not_empty"]).with_vars(vec![("channel_name", channel_name), ("users", user_ids)])
ErrorKind::RoomNotEmpty(name.to_string(), user_ids.clone()),
t!(["errors", "room_not_empty"]).with_vars(vec![("channel_name", name), ("users", user_ids)])
);
}

let rocketchat_channel_id = room.rocketchat_channel_id()?.unwrap_or_default();
let room_alias_id = Room::build_room_alias_id(self.config, &server.id, &rocketchat_channel_id)?;
let room_alias_id = channel.build_room_alias_id()?;
self.matrix_api.put_canonical_room_alias(room_id.clone(), None)?;
self.matrix_api.delete_room_alias(room_alias_id)?;

//TODO: Should we cleanup all the virtual users here?
let bot_user_id = self.config.matrix_bot_user_id()?;
let message = t!(["admin_room", "room_successfully_unbridged"]).with_vars(vec![("channel_name", channel_name.clone())]);
let message = t!(["admin_room", "room_successfully_unbridged"]).with_vars(vec![("channel_name", name.clone())]);
self.matrix_api.send_text_message_event(event.room_id.clone(), bot_user_id, message.l(DEFAULT_LANGUAGE))?;

Ok(info!(self.logger, "Successfully unbridged room {}", channel_name.clone()))
Ok(info!(self.logger, "Successfully unbridged room {}", name.clone()))
}

fn get_existing_rocketchat_server(&self, rocketchat_url: String) -> Result<RocketchatServer> {
Expand All @@ -363,23 +364,17 @@ impl<'a> CommandHandler<'a> {
let channels = rocketchat_api.channels_list()?;

let mut channel_list = "".to_string();
for channel in channels {
let formatter = if Room::is_bridged_for_user(
self.config,
self.logger,
self.matrix_api,
rocketchat_server_id,
&channel.id,
user_id,
)? {
for c in channels {
let channel = Channel::new(self.config, self.logger, self.matrix_api, c.id, rocketchat_server_id);
let formatter = if channel.is_bridged_for_user(user_id)? {
"**"
} else if channel.usernames.iter().any(|username| username == &display_name) {
} else if c.usernames.iter().any(|username| username == &display_name) {
"*"
} else {
""
};

channel_list = channel_list + "* " + formatter + &channel.name.unwrap_or(channel.id) + formatter + "\n\n";
channel_list = channel_list + "* " + formatter + &c.name.unwrap_or(channel.id) + formatter + "\n\n";
}

Ok(channel_list)
Expand Down
43 changes: 19 additions & 24 deletions src/matrix-rocketchat/handlers/events/membership_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ use std::collections::HashMap;
use std::convert::TryFrom;

use diesel::sqlite::SqliteConnection;
use diesel::Connection;
use iron::url::Host;
use ruma_events::room::member::{MemberEvent, MembershipState};
use ruma_identifiers::UserId;
use slog::Logger;
use serde_json::{self, Value};

use api::{MatrixApi, RocketchatApi};
use api::rocketchat::Channel;
use config::Config;
use errors::*;
use handlers::ErrorNotifier;
Expand All @@ -23,7 +21,7 @@ use models::Room;
/// Handles membership events for a specific room
pub struct MembershipHandler<'a> {
config: &'a Config,
connection: &'a SqliteConnection,
conn: &'a SqliteConnection,
logger: &'a Logger,
matrix_api: &'a MatrixApi,
room: &'a Room<'a>,
Expand All @@ -33,14 +31,14 @@ impl<'a> MembershipHandler<'a> {
/// Create a new `MembershipHandler`.
pub fn new(
config: &'a Config,
connection: &'a SqliteConnection,
conn: &'a SqliteConnection,
logger: &'a Logger,
matrix_api: &'a MatrixApi,
room: &'a Room<'a>,
) -> MembershipHandler<'a> {
MembershipHandler {
config: config,
connection: connection,
conn: conn,
logger: logger,
matrix_api: matrix_api,
room: room,
Expand Down Expand Up @@ -163,23 +161,21 @@ impl<'a> MembershipHandler<'a> {
return Ok(());
}

self.connection.transaction(|| {
match CommandHandler::build_help_message(self.connection, self.room, self.config.as_url.clone(), &inviter_id) {
Ok(body) => {
self.matrix_api.send_text_message_event(self.room.id.clone(), matrix_bot_user_id, body)?;
}
Err(err) => {
log::log_info(self.logger, &err);
}
match CommandHandler::build_help_message(self.conn, self.room, self.config.as_url.clone(), &inviter_id) {
Ok(body) => {
self.matrix_api.send_text_message_event(self.room.id.clone(), matrix_bot_user_id, body)?;
}

let room_name = t!(["defaults", "admin_room_display_name"]).l(DEFAULT_LANGUAGE);
if let Err(err) = self.matrix_api.set_room_name(self.room.id.clone(), room_name) {
Err(err) => {
log::log_info(self.logger, &err);
}
}

Ok(())
})
let room_name = t!(["defaults", "admin_room_display_name"]).l(DEFAULT_LANGUAGE);
if let Err(err) = self.matrix_api.set_room_name(self.room.id.clone(), room_name) {
log::log_info(self.logger, &err);
}

Ok(())
}

fn handle_user_join(&self) -> Result<()> {
Expand Down Expand Up @@ -236,38 +232,37 @@ impl<'a> MembershipHandler<'a> {
/// TODO: This feels like it's in the wrong place, where to move it?
pub fn add_virtual_users_to_room(
&self,
rocketchat_api: Box<RocketchatApi>,
channel: &Channel,
rocketchat_api: &RocketchatApi,
usernames: &[String],
rocketchat_server_id: String,
) -> Result<()> {
debug!(self.logger, "Starting to add virtual users to room {}", self.room.id);

let virtual_user_handler = VirtualUserHandler {
config: self.config,
connection: self.connection,
logger: self.logger,
matrix_api: self.matrix_api,
};

//TODO: Check if a max number of users per channel has to be defined to avoid problems when
//there are several thousand users in a channel.
let bot_user_id = self.config.matrix_bot_user_id()?;
for username in &channel.usernames {
for username in usernames.iter() {
let rocketchat_user = rocketchat_api.users_info(username)?;
let user_id =
virtual_user_handler.find_or_register(rocketchat_server_id.clone(), rocketchat_user.id, username.to_string())?;
virtual_user_handler.add_to_room(user_id, bot_user_id.clone(), self.room)?;
}

debug!(self.logger, "Successfully added {} virtual users to room {}", channel.usernames.len(), self.room.id);
debug!(self.logger, "Successfully added {} virtual users to room {}", usernames.len(), self.room.id);

Ok(())
}

fn handle_admin_room_setup_error(&self, err: &Error, matrix_bot_user_id: UserId) {
let error_notifier = ErrorNotifier {
config: self.config,
connection: self.connection,
connection: self.conn,
logger: self.logger,
matrix_api: self.matrix_api,
};
Expand Down
5 changes: 1 addition & 4 deletions src/matrix-rocketchat/handlers/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ pub mod forwarder;
pub mod membership_handler;
/// Handles message events
pub mod message_handler;
/// Creates and bridge rooms
pub mod room_handler;

pub use self::command_handler::CommandHandler;
pub use self::dispatcher::Dispatcher;
pub use self::forwarder::Forwarder;
pub use self::message_handler::MessageHandler;
pub use self::membership_handler::MembershipHandler;
pub use self::room_handler::RoomHandler;
pub use self::membership_handler::MembershipHandler;
65 changes: 0 additions & 65 deletions src/matrix-rocketchat/handlers/events/room_handler.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/matrix-rocketchat/handlers/iron/rocketchat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ impl Handler for Rocketchat {

let virtual_user_handler = VirtualUserHandler {
config: &self.config,
connection: &connection,
logger: &logger,
matrix_api: self.matrix_api.as_ref(),
};
Expand Down
12 changes: 6 additions & 6 deletions src/matrix-rocketchat/handlers/rocketchat/forwarder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use config::Config;
use errors::*;
use handlers::rocketchat::VirtualUserHandler;
use log;
use models::{RocketchatServer, Room, UserOnRocketchatServer};
use models::{Channel, RocketchatServer, Room, UserOnRocketchatServer};

const RESEND_THRESHOLD_IN_SECONDS: i64 = 3;

Expand Down Expand Up @@ -154,11 +154,11 @@ impl<'a> Forwarder<'a> {
}

fn prepare_room_for_channel(&self, server: &RocketchatServer, message: &Message) -> Result<Option<Room>> {
let room_id =
match Room::matrix_id_from_rocketchat_channel_id(self.config, self.matrix_api, &server.id, &message.channel_id)? {
Some(room_id) => room_id,
None => return Ok(None),
};
let channel = Channel::new(self.config, self.logger, self.matrix_api, message.channel_id.clone(), &server.id);
let room_id = match channel.matrix_id()? {
Some(room_id) => room_id,
None => return Ok(None),
};

let inviting_user_id = self.config.matrix_bot_user_id()?;
let user_id = message.user_id.clone();
Expand Down

0 comments on commit f19b1bd

Please sign in to comment.