Skip to content

Commit 19c83d7

Browse files
committed
refactor(chatroom): 重构用户名补全功能,优化相关结构和逻辑
1 parent dfeeb47 commit 19c83d7

9 files changed

Lines changed: 98 additions & 52 deletions

File tree

client/src/app.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use fishpi_rust::FishPi;
44
use std::sync::Arc;
55

66
use crate::commands::{CommandContext, CommandRegistry};
7-
use crate::ui::CrosstermInputHandler;
7+
use crate::ui::{CrosstermInputHandler, GLOBAL_COMMAND_CONTEXT};
88
use crate::utils::AuthService;
99

1010
pub struct App {
@@ -161,6 +161,7 @@ impl App {
161161

162162
async fn main_loop(&mut self) -> Result<()> {
163163
let context = CommandContext::new((*self.client).clone());
164+
GLOBAL_COMMAND_CONTEXT.set(context.clone()).ok();
164165

165166
loop {
166167
match self

client/src/commands/handlers/chatroom.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@ use crossterm::{
1818
cursor, execute,
1919
terminal::{Clear, ClearType},
2020
};
21-
use fishpi_rust::{ChatRoomDataContent, ChatRoomMessage, ChatRoomUser, GestureType, RedPacketType};
21+
use fishpi_rust::{ChatRoomDataContent, ChatRoomMessage, GestureType, RedPacketType};
2222
use lru::LruCache;
2323
use std::borrow::Cow;
2424
use std::io::{self, Write};
2525
use std::sync::{Arc, Mutex};
2626

2727
pub struct ChatroomCommand {
2828
context: CommandContext,
29-
online_users: Arc<Mutex<Vec<ChatRoomUser>>>,
3029
redpacket_handler: RedpacketCommand,
3130
filter_handler: FilterCommand,
3231
message_cache: Arc<Mutex<LruCache<String, ChatRoomMessage>>>,
@@ -36,7 +35,6 @@ impl ChatroomCommand {
3635
pub fn new(context: CommandContext) -> Self {
3736
Self {
3837
context: context.clone(),
39-
online_users: Arc::new(Mutex::new(vec![])),
4038
redpacket_handler: RedpacketCommand::new(context),
4139
filter_handler: FilterCommand::new(),
4240
message_cache: Arc::new(Mutex::new(LruCache::new(
@@ -89,10 +87,7 @@ impl Command for ChatroomCommand {
8987

9088
impl ChatroomCommand {
9189
async fn chatroom_loop(&self) -> Result<()> {
92-
let completer = CommandCompleter {
93-
commands: vec![],
94-
users: Arc::clone(&self.online_users),
95-
};
90+
let completer = CommandCompleter { commands: vec![] };
9691
let mut input_handler = CrosstermInputHandler::with_completer(completer);
9792
input_handler.set_commands(vec![
9893
CommandItem {
@@ -197,7 +192,10 @@ impl ChatroomCommand {
197192
let stats = crate::utils::GESTURE_STATS.lock().unwrap();
198193
let total: u64 = stats.iter().sum();
199194
if total == 0 {
200-
println!("石头: {}, 剪刀: {}, 布: {},总数: 0", stats[0], stats[1], stats[2]);
195+
println!(
196+
"石头: {}, 剪刀: {}, 布: {},总数: 0",
197+
stats[0], stats[1], stats[2]
198+
);
201199
} else {
202200
let rock_pct = stats[0] as f64 / total as f64 * 100.0;
203201
let scissors_pct = stats[1] as f64 / total as f64 * 100.0;
@@ -335,7 +333,6 @@ impl ChatroomCommand {
335333
}
336334

337335
async fn register_message_handler(&self) -> Result<()> {
338-
let online_users = Arc::clone(&self.online_users);
339336
let auth = Arc::clone(&self.context.auth);
340337
let client = Arc::clone(&self.context.client);
341338
let redpacket_cache = Arc::clone(&self.redpacket_handler.redpacket_cache);
@@ -348,7 +345,6 @@ impl ChatroomCommand {
348345
.client
349346
.chatroom
350347
.add_listener(move |data| {
351-
let online_users = Arc::clone(&online_users);
352348
let auth = Arc::clone(&auth);
353349
let client = Arc::clone(&client);
354350
let redpacket_cache = Arc::clone(&redpacket_cache);
@@ -491,11 +487,7 @@ impl ChatroomCommand {
491487
ChatRoomDataContent::Custom(custom) => {
492488
println!("\r[{}]", custom.cyan());
493489
}
494-
ChatRoomDataContent::OnlineUsers(online_user, ..) => {
495-
if let Ok(mut users) = online_users.lock() {
496-
*users = online_user;
497-
}
498-
}
490+
ChatRoomDataContent::OnlineUsers(..) => {}
499491
ChatRoomDataContent::Discuss(topic) => {
500492
println!("\r{}: {}", "💬 话题变更".yellow().bold(), topic.yellow());
501493
}

client/src/commands/handlers/redpacket.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use crate::commands::{Command, CommandContext, CommandResult};
2+
use crate::utils::random_gesture;
23
use anyhow::Result;
34
use async_trait::async_trait;
45
use colored::*;
56
use fishpi_rust::{GestureType, RedPacketMessage, RedPacketType};
67
use std::collections::HashMap;
78
use std::sync::{Arc, Mutex};
8-
use crate::utils::random_gesture;
99

1010
pub struct RedpacketCommand {
1111
context: CommandContext,

client/src/ui/mod.rs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
use crate::commands::CommandContext;
12
use colored::*;
2-
use fishpi_rust::ChatRoomUser;
3+
use fishpi_rust::api::ChatroomApi;
4+
use once_cell::sync::OnceCell;
35
use rustyline::completion::{Completer, Pair};
46
use rustyline::error::ReadlineError;
57
use rustyline::highlight::Highlighter;
@@ -9,7 +11,8 @@ use rustyline::validate::Validator;
911
use rustyline::{CompletionType, Config, Editor};
1012
use rustyline::{Context, Helper};
1113
use std::io;
12-
use std::sync::{Arc, Mutex};
14+
15+
pub static GLOBAL_COMMAND_CONTEXT: OnceCell<CommandContext> = OnceCell::new();
1316

1417
pub struct CommandItem {
1518
pub name: &'static str,
@@ -19,15 +22,11 @@ pub struct CommandItem {
1922
/// 命令补全器
2023
pub struct CommandCompleter {
2124
pub commands: Vec<CommandItem>,
22-
pub users: Arc<Mutex<Vec<ChatRoomUser>>>,
2325
}
2426

2527
impl CommandCompleter {
2628
fn new() -> Self {
27-
Self {
28-
commands: vec![],
29-
users: Arc::new(Mutex::new(vec![])),
30-
}
29+
Self { commands: vec![] }
3130
}
3231

3332
fn set_commands(&mut self, commands: Vec<CommandItem>) {
@@ -77,21 +76,33 @@ impl Completer for CommandCompleter {
7776
// @用户名补全
7877
if let Some(at_pos) = line[..pos].rfind('@') {
7978
let prefix = &line[at_pos + 1..pos];
80-
let users = self.users.lock().unwrap();
81-
let candidates: Vec<Pair> = users
82-
.iter()
83-
.filter(|user| {
84-
user.user_name
85-
.to_lowercase()
86-
.starts_with(&prefix.to_lowercase())
87-
})
88-
.map(|user| Pair {
89-
display: format!("@{}", user.user_name.cyan()),
90-
replacement: user.user_name.clone(),
91-
})
92-
.collect();
93-
94-
return Ok((at_pos + 1, candidates));
79+
if !prefix.is_empty() {
80+
if let Some(ctx) = GLOBAL_COMMAND_CONTEXT.get() {
81+
let prefix_owned = prefix.to_string();
82+
let ctx_clone = ctx.clone();
83+
let candidates = std::thread::scope(|s| {
84+
let handle = s.spawn(move || {
85+
let rt = tokio::runtime::Runtime::new().unwrap();
86+
rt.block_on(async move {
87+
let api = ChatroomApi::new(ctx_clone.client.api_client.clone());
88+
match api.autocomplete_username(&prefix_owned).await {
89+
Ok(api_users) => api_users
90+
.into_iter()
91+
.map(|u| Pair {
92+
display: format!("@{}", u.user_name.cyan()),
93+
replacement: u.user_name,
94+
})
95+
.collect(),
96+
Err(_) => vec![],
97+
}
98+
})
99+
});
100+
handle.join().unwrap_or_else(|_| vec![])
101+
});
102+
103+
return Ok((at_pos + 1, candidates));
104+
}
105+
}
95106
}
96107

97108
if line.trim().is_empty() {

client/src/utils/mod.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ pub use auth::AuthService;
44

55
use chrono::{Local, TimeZone};
66
use colored::*;
7-
use regex::Regex;
8-
use std::sync::{Arc, Mutex};
97
use once_cell::sync::Lazy;
8+
use regex::Regex;
9+
use serde::{Deserialize, Serialize};
1010
use std::fs;
1111
use std::path::Path;
12-
use serde::{Serialize, Deserialize};
12+
use std::sync::{Arc, Mutex};
1313

1414
const GESTURE_STATS_FILE: &str = "gesture_stats.json";
1515

@@ -34,9 +34,8 @@ pub fn load_gesture_stats() -> [u64; 3] {
3434
[0; 3]
3535
}
3636

37-
pub static GESTURE_STATS: Lazy<Arc<Mutex<[u64; 3]>>> = Lazy::new(|| {
38-
Arc::new(Mutex::new(load_gesture_stats()))
39-
});
37+
pub static GESTURE_STATS: Lazy<Arc<Mutex<[u64; 3]>>> =
38+
Lazy::new(|| Arc::new(Mutex::new(load_gesture_stats())));
4039

4140
//随机猜拳
4241
pub fn random_gesture() -> u8 {

src/api/chatroom_api.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::api::client::ApiClient;
22
use crate::models::chatroom::{
3-
BarrageCost, ChatRoomMessage, ChatRoomNode, ChatRoomNodeInfo, ChatRoomQueryMode, ChatSource,
4-
MuteItem,
3+
AutoCompleteUsername, BarrageCost, ChatRoomMessage, ChatRoomNode, ChatRoomNodeInfo,
4+
ChatRoomQueryMode, ChatSource, MuteItem,
55
};
66
use crate::models::user::ApiResponse;
77
use anyhow::{Result, anyhow};
@@ -380,4 +380,22 @@ impl ChatroomApi {
380380
avaliable,
381381
})
382382
}
383+
384+
/// 用户名补全接口
385+
///
386+
/// 返回用户名 Vec<AutoCompleteUsername>
387+
pub async fn autocomplete_username(&self, prefix: &str) -> Result<Vec<AutoCompleteUsername>> {
388+
let token = self.check_token("用户名补全").await?;
389+
let params = self.build_params(HashMap::new(), token);
390+
let data = json!({ "name": prefix });
391+
let response = self
392+
.client
393+
.post::<ApiResponse<Vec<AutoCompleteUsername>>>("/users/names", Some(params), data)
394+
.await?;
395+
// 失败返回空列表
396+
if response.code != 0 || response.data.is_none() {
397+
return Err(anyhow!("获取用户名失败"));
398+
}
399+
Ok(response.data.unwrap_or_default())
400+
}
383401
}

src/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ pub mod services;
6565

6666
// 导出常用类型到顶层命名空间
6767
pub use models::chatroom::{
68-
BarrageCost, BarragerMsg, ChatContentType, ChatRoomData, ChatRoomDataContent, ChatRoomMessage,
69-
ChatRoomMessageType, ChatRoomNode, ChatRoomNodeInfo, ChatRoomQueryMode, ChatRoomUser,
70-
ChatSource, MusicMsg, MuteItem, SpecialMessageContent, WeatherMsg, WeatherMsgData,
71-
WebSocketMessage,
68+
AutoCompleteUsername, BarrageCost, BarragerMsg, ChatContentType, ChatRoomData,
69+
ChatRoomDataContent, ChatRoomMessage, ChatRoomMessageType, ChatRoomNode, ChatRoomNodeInfo,
70+
ChatRoomQueryMode, ChatRoomUser, ChatSource, MusicMsg, MuteItem, SpecialMessageContent,
71+
WeatherMsg, WeatherMsgData, WebSocketMessage,
7272
};
7373

7474
pub use models::chat::{
@@ -110,7 +110,7 @@ use api::{
110110
/// FishPi API 客户端主类
111111
#[derive(Debug, Clone)]
112112
pub struct FishPi {
113-
api_client: ApiClient,
113+
pub api_client: ApiClient,
114114
pub user: UserService,
115115
pub chatroom: ChatroomService,
116116
pub redpacket: RedpacketService,

src/models/chatroom.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,22 @@ pub struct ChatRoomNodeInfo {
10011001
pub avaliable: Vec<ChatRoomNode>,
10021002
}
10031003

1004+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1005+
pub struct AutoCompleteUsername {
1006+
#[serde(rename = "userNameLowerCase")]
1007+
pub username_lowercase: String,
1008+
#[serde(rename = "userAvatarURL")]
1009+
pub useravatar_url: String,
1010+
#[serde(rename = "userAvatarURL20")]
1011+
pub uservatar_url20: String,
1012+
#[serde(rename = "userName")]
1013+
pub user_name: String,
1014+
#[serde(rename = "userAvatarURL210")]
1015+
pub uservatar_url210: String,
1016+
#[serde(rename = "userAvatarURL48")]
1017+
pub uservatar_url48: String,
1018+
}
1019+
10041020
// 聊天室数据类型
10051021
#[derive(Debug, Clone)]
10061022
pub struct ChatRoomData {

src/services/chatroom_service.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::AutoCompleteUsername;
12
use crate::api::ChatroomApi;
23
use crate::api::client::ApiClient;
34
use crate::models::chatroom::{
@@ -126,6 +127,14 @@ impl ChatroomService {
126127
}
127128
}
128129

130+
/// 用户名补全
131+
pub async fn autocomplete(&self, prefix: &str) -> Response<Vec<AutoCompleteUsername>> {
132+
self.call_api("用户名补全", || {
133+
self.chatroom_api.autocomplete_username(prefix)
134+
})
135+
.await
136+
}
137+
129138
/// 发送消息
130139
pub async fn send<'a>(
131140
&self,

0 commit comments

Comments
 (0)