Skip to main content

flare_core/server/device/
manager.rs

1//! 设备管理器
2//!
3//! 管理用户设备的在线状态,处理设备冲突
4
5use crate::common::device::{DeviceConflictStrategy, DeviceInfo, DevicePlatform};
6use crate::common::error::Result;
7use std::collections::{HashMap, HashSet};
8use std::sync::Arc;
9use tokio::sync::RwLock;
10use tracing::{debug, info, warn};
11
12/// 用户设备信息
13#[derive(Debug, Clone)]
14struct UserDevice {
15    /// 连接 ID
16    connection_id: String,
17    /// 设备信息
18    device_info: DeviceInfo,
19}
20
21/// 设备管理器
22///
23/// 管理用户设备的在线状态,根据冲突策略处理设备登录
24pub struct DeviceManager {
25    /// 用户ID -> 设备列表(连接ID -> 设备信息)
26    user_devices: Arc<RwLock<HashMap<String, HashMap<String, UserDevice>>>>,
27    /// 冲突策略
28    conflict_strategy: DeviceConflictStrategy,
29}
30
31impl DeviceManager {
32    /// 创建新的设备管理器
33    pub fn new(conflict_strategy: DeviceConflictStrategy) -> Self {
34        Self {
35            user_devices: Arc::new(RwLock::new(HashMap::new())),
36            conflict_strategy,
37        }
38    }
39
40    /// 添加设备(检查冲突)
41    ///
42    /// # 参数
43    /// - `user_id`: 用户 ID
44    /// - `connection_id`: 连接 ID
45    /// - `device_info`: 设备信息
46    ///
47    /// # 返回
48    /// - `Ok(Vec<String>)`: 需要被踢掉的连接 ID 列表(可能为空)
49    /// - `Err`: 如果添加失败
50    pub async fn add_device(
51        &self,
52        user_id: &str,
53        connection_id: String,
54        device_info: DeviceInfo,
55    ) -> Result<Vec<String>> {
56        let mut user_devices = self.user_devices.write().await;
57
58        // 获取用户现有设备
59        let user_device_map = user_devices
60            .entry(user_id.to_string())
61            .or_insert_with(HashMap::new);
62
63        // 收集现有设备的平台类型
64        let existing_platforms: HashSet<DevicePlatform> = user_device_map
65            .values()
66            .map(|d| d.device_info.platform.clone())
67            .collect();
68
69        info!(
70            "[DeviceManager] 添加设备: user_id={}, connection_id={}, platform={:?}, 现有设备数={}, 现有平台={:?}",
71            user_id,
72            connection_id,
73            device_info.platform,
74            user_device_map.len(),
75            existing_platforms
76        );
77
78        // 检查冲突(先克隆 platform,避免移动 device_info)
79        let platform = device_info.platform.clone();
80        let conflicts = match self
81            .conflict_strategy
82            .check_conflict(platform.clone(), &existing_platforms)
83        {
84            Ok(_) => {
85                debug!("[DeviceManager] 无冲突,允许添加设备");
86                Vec::new()
87            }
88            Err(conflict_platforms) => {
89                info!(
90                    "[DeviceManager] 检测到冲突: 新平台={:?}, 冲突平台={:?}",
91                    platform, conflict_platforms
92                );
93                // 找到需要踢掉的连接(确保不包含新连接本身)
94                let mut conflict_connections = Vec::new();
95                for (conn_id, device) in user_device_map.iter() {
96                    // 确保不包含新连接本身
97                    if conn_id == &connection_id {
98                        continue;
99                    }
100                    if conflict_platforms.contains(&device.device_info.platform) {
101                        info!(
102                            "[DeviceManager] 发现冲突连接: connection_id={}, platform={:?} (新连接ID: {})",
103                            conn_id, device.device_info.platform, connection_id
104                        );
105                        conflict_connections.push(conn_id.clone());
106                    }
107                }
108                if conflict_connections.is_empty() {
109                    warn!(
110                        "[DeviceManager] 警告:检测到冲突但未找到冲突连接,现有设备: {:?}",
111                        user_device_map.keys().collect::<Vec<_>>()
112                    );
113                }
114                conflict_connections
115            }
116        };
117
118        // 移除冲突的设备
119        for conn_id in &conflicts {
120            user_device_map.remove(conn_id);
121            info!("[DeviceManager] 已移除冲突设备: connection_id={}", conn_id);
122        }
123
124        // 添加新设备
125        user_device_map.insert(
126            connection_id.clone(),
127            UserDevice {
128                connection_id: connection_id.clone(),
129                device_info,
130            },
131        );
132        info!(
133            "[DeviceManager] 新设备已添加: user_id={}, connection_id={}, 当前设备数={}",
134            user_id,
135            connection_id,
136            user_device_map.len()
137        );
138
139        Ok(conflicts)
140    }
141
142    /// 移除设备
143    pub async fn remove_device(&self, user_id: &str, connection_id: &str) -> Result<()> {
144        let mut user_devices = self.user_devices.write().await;
145
146        if let Some(devices) = user_devices.get_mut(user_id) {
147            devices.remove(connection_id);
148
149            // 如果用户没有设备了,移除用户
150            if devices.is_empty() {
151                user_devices.remove(user_id);
152            }
153        }
154
155        Ok(())
156    }
157
158    /// 获取用户的所有设备
159    pub async fn get_user_devices(&self, user_id: &str) -> Vec<DeviceInfo> {
160        let user_devices = self.user_devices.read().await;
161
162        user_devices
163            .get(user_id)
164            .map(|devices| devices.values().map(|d| d.device_info.clone()).collect())
165            .unwrap_or_default()
166    }
167
168    /// 获取用户的所有连接 ID
169    pub async fn get_user_connections(&self, user_id: &str) -> Vec<String> {
170        let user_devices = self.user_devices.read().await;
171
172        user_devices
173            .get(user_id)
174            .map(|devices| devices.keys().cloned().collect())
175            .unwrap_or_default()
176    }
177
178    /// 获取设备的连接 ID
179    pub async fn get_device_connection(&self, user_id: &str, device_id: &str) -> Option<String> {
180        let user_devices = self.user_devices.read().await;
181
182        user_devices.get(user_id).and_then(|devices| {
183            devices
184                .values()
185                .find(|d| d.device_info.device_id == device_id)
186                .map(|d| d.connection_id.clone())
187        })
188    }
189
190    /// 更新冲突策略
191    pub fn update_strategy(&mut self, strategy: DeviceConflictStrategy) {
192        self.conflict_strategy = strategy;
193    }
194}