Enhance README with CLI room checking instructions and implement room name resolution in command handling. Updated handle_init_command and handle_join_command to use resolved room names, improving room access validation. Added CLI command handling in main.rs to list available rooms from the database or fallback configuration.
This commit is contained in:
18
README.md
18
README.md
@@ -108,6 +108,24 @@ In `YourPart3/backend/config/chatBridge.json` sollte stehen:
|
||||
|
||||
Dann verbindet sich die bestehende Bridge (`chatTcpBridge.js`) direkt mit `yourchat2`.
|
||||
|
||||
## Raeume per CLI pruefen
|
||||
|
||||
Die Raumdefinitionen kommen aus `chat.room` (bei gesetztem `CHAT_DB_URL`).
|
||||
Ohne DB-Verbindung gibt es einen Fallback mit `lobby`.
|
||||
|
||||
Pruefen auf Kommandozeile:
|
||||
|
||||
```bash
|
||||
cd /home/tsschulz/Programs/yourchat2
|
||||
CHAT_DB_URL='postgres://user:pass@host:5432/dbname' ./target/release/yourchat2 --list-rooms
|
||||
```
|
||||
|
||||
Wenn der Service ueber systemd laeuft und die Variablen in `/etc/yourchat2/yourchat2.env` stehen:
|
||||
|
||||
```bash
|
||||
sudo -u tsschulz bash -lc 'set -a; source /etc/yourchat2/yourchat2.env; set +a; /usr/local/bin/yourchat2 --list-rooms'
|
||||
```
|
||||
|
||||
## Systemd (optional)
|
||||
|
||||
Es liegt eine Produktions-nahe Unit-Datei `yourchat2.service` im Projekt.
|
||||
|
||||
@@ -148,7 +148,7 @@ async fn handle_init_command(
|
||||
let room_name = normalize_room_name(command.room.as_deref().unwrap_or("lobby"));
|
||||
let room_password = command.password.clone().unwrap_or_default();
|
||||
|
||||
let (token, user_name) = {
|
||||
let (token, user_name, actual_room_name) = {
|
||||
let mut guard = state.write().await;
|
||||
if guard.logged_in_names.contains(&requested_user_name)
|
||||
&& guard
|
||||
@@ -160,8 +160,13 @@ async fn handle_init_command(
|
||||
send_error(client_id, Arc::clone(&state), "loggedin").await;
|
||||
return;
|
||||
}
|
||||
let Some(resolved_room_name) = resolve_room_name(&guard, &room_name) else {
|
||||
drop(guard);
|
||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
||||
return;
|
||||
};
|
||||
if !room_access_allowed(
|
||||
guard.room_meta.get(&room_name),
|
||||
guard.room_meta.get(&resolved_room_name),
|
||||
&profile.display_name,
|
||||
profile.falukant_user_id,
|
||||
profile.age,
|
||||
@@ -187,7 +192,7 @@ async fn handle_init_command(
|
||||
client.age = profile.age;
|
||||
client.rights = profile.rights.clone();
|
||||
client.logged_in = true;
|
||||
client.room = room_name.clone();
|
||||
client.room = resolved_room_name.clone();
|
||||
|
||||
let mut new_token = None;
|
||||
if client.token.is_none() {
|
||||
@@ -218,8 +223,12 @@ async fn handle_init_command(
|
||||
members.remove(&client_id);
|
||||
}
|
||||
}
|
||||
guard.rooms.entry(room_name.clone()).or_default().insert(client_id);
|
||||
(token, user_name)
|
||||
guard
|
||||
.rooms
|
||||
.entry(resolved_room_name.clone())
|
||||
.or_default()
|
||||
.insert(client_id);
|
||||
(token, user_name, resolved_room_name)
|
||||
};
|
||||
|
||||
state::send_to_client(
|
||||
@@ -232,13 +241,13 @@ async fn handle_init_command(
|
||||
state::send_to_client(
|
||||
client_id,
|
||||
Arc::clone(&state),
|
||||
json!({"type":5, "message":"room_entered", "to": room_name}),
|
||||
json!({"type":5, "message":"room_entered", "to": actual_room_name}),
|
||||
)
|
||||
.await;
|
||||
state::broadcast_room(
|
||||
&room_name,
|
||||
&actual_room_name,
|
||||
Arc::clone(&state),
|
||||
json!({"type":"system","message": format!("{user_name} joined {room_name}")}),
|
||||
json!({"type":"system","message": format!("{user_name} joined {actual_room_name}")}),
|
||||
Some(client_id),
|
||||
)
|
||||
.await;
|
||||
@@ -255,8 +264,13 @@ async fn handle_join_command(
|
||||
}
|
||||
let room = normalize_room_name(command.room.as_deref().or(command.name.as_deref()).unwrap_or("lobby"));
|
||||
let password = command.password.clone().unwrap_or_default();
|
||||
let (from_room, user_name) = {
|
||||
let (from_room, user_name, actual_room_name) = {
|
||||
let mut guard = state.write().await;
|
||||
let Some(resolved_room) = resolve_room_name(&guard, &room) else {
|
||||
drop(guard);
|
||||
send_error(client_id, Arc::clone(&state), "room_not_found_or_join_failed").await;
|
||||
return;
|
||||
};
|
||||
let (name_for_check, falukant_user_id, age) = {
|
||||
let Some(client) = guard.clients.get(&client_id) else {
|
||||
return;
|
||||
@@ -264,7 +278,7 @@ async fn handle_join_command(
|
||||
(client.user_name.clone(), client.falukant_user_id, client.age)
|
||||
};
|
||||
if !room_access_allowed(
|
||||
guard.room_meta.get(&room),
|
||||
guard.room_meta.get(&resolved_room),
|
||||
&name_for_check,
|
||||
falukant_user_id,
|
||||
age,
|
||||
@@ -279,14 +293,14 @@ async fn handle_join_command(
|
||||
};
|
||||
let from_room = client.room.clone();
|
||||
let user_name = client.user_name.clone();
|
||||
client.room = room.clone();
|
||||
client.room = resolved_room.clone();
|
||||
if !from_room.is_empty() {
|
||||
if let Some(members) = guard.rooms.get_mut(&from_room) {
|
||||
members.remove(&client_id);
|
||||
}
|
||||
}
|
||||
guard.rooms.entry(room.clone()).or_default().insert(client_id);
|
||||
(from_room, user_name)
|
||||
guard.rooms.entry(resolved_room.clone()).or_default().insert(client_id);
|
||||
(from_room, user_name, resolved_room)
|
||||
};
|
||||
|
||||
if !from_room.is_empty() && from_room != room {
|
||||
@@ -301,7 +315,7 @@ async fn handle_join_command(
|
||||
state::send_to_client(
|
||||
client_id,
|
||||
Arc::clone(&state),
|
||||
json!({"type":5, "message":"room_entered", "to": room}),
|
||||
json!({"type":5, "message":"room_entered", "to": actual_room_name}),
|
||||
)
|
||||
.await;
|
||||
state::send_room_list(client_id, Arc::clone(&state)).await;
|
||||
@@ -754,7 +768,7 @@ async fn handle_unknown_command(client_id: ClientId, command: &Command, state: A
|
||||
|
||||
fn room_access_allowed(
|
||||
room_meta: Option<&RoomMeta>,
|
||||
user_name: &str,
|
||||
_user_name: &str,
|
||||
falukant_user_id: Option<i32>,
|
||||
age: Option<i32>,
|
||||
provided_password: &str,
|
||||
@@ -792,17 +806,21 @@ fn room_access_allowed(
|
||||
}
|
||||
}
|
||||
|
||||
if !room.is_public {
|
||||
if room.owner_id.is_none() {
|
||||
return false;
|
||||
}
|
||||
if user_name.trim().is_empty() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn resolve_room_name(state: &ChatState, requested: &str) -> Option<String> {
|
||||
if state.room_meta.contains_key(requested) {
|
||||
return Some(requested.to_string());
|
||||
}
|
||||
let requested_lower = requested.to_lowercase();
|
||||
state
|
||||
.room_meta
|
||||
.keys()
|
||||
.find(|name| name.to_lowercase() == requested_lower)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
fn normalize_room_name(input: &str) -> String {
|
||||
let trimmed = input.trim();
|
||||
if trimmed.is_empty() {
|
||||
|
||||
45
src/main.rs
45
src/main.rs
@@ -38,6 +38,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
allowed_users: db::parse_allowed_users(),
|
||||
db_client,
|
||||
});
|
||||
if handle_cli_commands().as_deref() == Some("--list-rooms") {
|
||||
print_rooms_for_cli(&config).await?;
|
||||
return Ok(());
|
||||
}
|
||||
let rooms = db::load_room_configs(&config).await.unwrap_or_else(|_| {
|
||||
vec![types::RoomMeta {
|
||||
name: "lobby".to_string(),
|
||||
@@ -212,6 +216,47 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_cli_commands() -> Option<String> {
|
||||
env::args().nth(1)
|
||||
}
|
||||
|
||||
async fn print_rooms_for_cli(
|
||||
config: &ServerConfig,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let rooms = db::load_room_configs(config)
|
||||
.await
|
||||
.map_err(std::io::Error::other)?;
|
||||
|
||||
println!(
|
||||
"yourchat2 rooms source: {}",
|
||||
if config.db_client.is_some() { "database" } else { "fallback" }
|
||||
);
|
||||
println!(
|
||||
"{:<30} {:<8} {:<8} {:<8} {:<10}",
|
||||
"name", "public", "min_age", "max_age", "password"
|
||||
);
|
||||
println!("{}", "-".repeat(72));
|
||||
for room in rooms {
|
||||
println!(
|
||||
"{:<30} {:<8} {:<8} {:<8} {:<10}",
|
||||
room.name,
|
||||
if room.is_public { "yes" } else { "no" },
|
||||
room.min_age
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|| "-".to_string()),
|
||||
room.max_age
|
||||
.map(|v| v.to_string())
|
||||
.unwrap_or_else(|| "-".to_string()),
|
||||
if room.password.as_deref().unwrap_or("").is_empty() {
|
||||
"none"
|
||||
} else {
|
||||
"set"
|
||||
},
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_client<S>(
|
||||
stream: S,
|
||||
state: Arc<RwLock<ChatState>>,
|
||||
|
||||
@@ -78,6 +78,7 @@ pub(crate) struct DiceGame {
|
||||
pub(crate) total_scores: HashMap<ClientId, i32>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct RoomMeta {
|
||||
pub(crate) name: String,
|
||||
|
||||
Reference in New Issue
Block a user