manager.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. package device
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "iot-base-station/pkg/database"
  7. "iot-base-station/pkg/security"
  8. "github.com/go-redis/redis/v8"
  9. "go.uber.org/zap"
  10. "gorm.io/gorm"
  11. )
  12. // Manager 设备管理器
  13. type Manager struct {
  14. db *gorm.DB
  15. redis *redis.Client
  16. logger *zap.Logger
  17. }
  18. // NewManager 创建设备管理器
  19. func NewManager(db *gorm.DB, redis *redis.Client, logger *zap.Logger) *Manager {
  20. return &Manager{
  21. db: db,
  22. redis: redis,
  23. logger: logger,
  24. }
  25. }
  26. // CreateDevice 创建设备
  27. func (m *Manager) CreateDevice(ctx context.Context, req *CreateDeviceRequest) (*DeviceResponse, error) {
  28. // 生成设备ID
  29. deviceID := generateDeviceID(req.Type)
  30. // 创建设备对象
  31. device := &Device{
  32. ID: deviceID,
  33. Name: req.Name,
  34. Type: req.Type,
  35. Protocol: req.Protocol,
  36. Status: StatusOffline,
  37. Metadata: req.Metadata,
  38. Config: req.Config,
  39. Location: req.Location,
  40. Firmware: FirmwareInfo{
  41. Version: "1.0.0",
  42. ReleaseDate: time.Now(),
  43. },
  44. }
  45. // 保存到数据库
  46. if err := m.db.WithContext(ctx).Create(device).Error; err != nil {
  47. m.logger.Error("Failed to create device", zap.Error(err))
  48. return nil, fmt.Errorf("failed to create device: %w", err)
  49. }
  50. // 创建设备事件
  51. event := &DeviceEvent{
  52. ID: generateEventID(),
  53. DeviceID: deviceID,
  54. Type: EventConnect,
  55. Severity: SeverityInfo,
  56. Message: "设备已创建",
  57. Timestamp: time.Now(),
  58. }
  59. if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
  60. m.logger.Error("Failed to create device event", zap.Error(err))
  61. }
  62. m.logger.Info("Device created", zap.String("device_id", deviceID))
  63. return &device.ToResponse(), nil
  64. }
  65. // ListDevices 获取设备列表
  66. func (m *Manager) ListDevices(ctx context.Context, page, pageSize int, deviceType string) ([]DeviceResponse, int64, error) {
  67. var devices []Device
  68. var total int64
  69. query := m.db.WithContext(ctx).Model(&Device{})
  70. // 按类型筛选
  71. if deviceType != "" {
  72. query = query.Where("type = ?", deviceType)
  73. }
  74. // 获取总数
  75. if err := query.Count(&total).Error; err != nil {
  76. m.logger.Error("Failed to count devices", zap.Error(err))
  77. return nil, 0, fmt.Errorf("failed to count devices: %w", err)
  78. }
  79. // 分页查询
  80. offset := (page - 1) * pageSize
  81. if err := query.Offset(offset).Limit(pageSize).Find(&devices).Error; err != nil {
  82. m.logger.Error("Failed to list devices", zap.Error(err))
  83. return nil, 0, fmt.Errorf("failed to list devices: %w", err)
  84. }
  85. // 转换为响应格式
  86. responses := make([]DeviceResponse, len(devices))
  87. for i, device := range devices {
  88. responses[i] = device.ToResponse()
  89. }
  90. return responses, total, nil
  91. }
  92. // GetDevice 获取设备详情
  93. func (m *Manager) GetDevice(ctx context.Context, deviceID string) (*DeviceResponse, error) {
  94. var device Device
  95. if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
  96. if err == gorm.ErrRecordNotFound {
  97. return nil, fmt.Errorf("device not found")
  98. }
  99. m.logger.Error("Failed to get device", zap.Error(err))
  100. return nil, fmt.Errorf("failed to get device: %w", err)
  101. }
  102. return &device.ToResponse(), nil
  103. }
  104. // UpdateDevice 更新设备信息
  105. func (m *Manager) UpdateDevice(ctx context.Context, deviceID string, req *UpdateDeviceRequest) (*DeviceResponse, error) {
  106. var device Device
  107. // 查询设备
  108. if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
  109. if err == gorm.ErrRecordNotFound {
  110. return nil, fmt.Errorf("device not found")
  111. }
  112. m.logger.Error("Failed to get device", zap.Error(err))
  113. return nil, fmt.Errorf("failed to get device: %w", err)
  114. }
  115. // 更新字段
  116. if req.Name != "" {
  117. device.Name = req.Name
  118. }
  119. if req.Metadata != nil {
  120. device.Metadata = req.Metadata
  121. }
  122. if req.Config.ReportInterval > 0 {
  123. device.Config.ReportInterval = req.Config.ReportInterval
  124. }
  125. if req.Config.Threshold != nil {
  126. device.Config.Threshold = req.Config.Threshold
  127. }
  128. if req.Location.Address != "" {
  129. device.Location = req.Location
  130. }
  131. // 保存更新
  132. if err := m.db.WithContext(ctx).Save(&device).Error; err != nil {
  133. m.logger.Error("Failed to update device", zap.Error(err))
  134. return nil, fmt.Errorf("failed to update device: %w", err)
  135. }
  136. // 创建配置更新事件
  137. event := &DeviceEvent{
  138. ID: generateEventID(),
  139. DeviceID: deviceID,
  140. Type: EventConfig,
  141. Severity: SeverityInfo,
  142. Message: "设备配置已更新",
  143. Timestamp: time.Now(),
  144. }
  145. if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
  146. m.logger.Error("Failed to create device event", zap.Error(err))
  147. }
  148. m.logger.Info("Device updated", zap.String("device_id", deviceID))
  149. return &device.ToResponse(), nil
  150. }
  151. // DeleteDevice 删除设备
  152. func (m *Manager) DeleteDevice(ctx context.Context, deviceID string) error {
  153. // 软删除设备
  154. if err := m.db.WithContext(ctx).Delete(&Device{}, "id = ?", deviceID).Error; err != nil {
  155. m.logger.Error("Failed to delete device", zap.Error(err))
  156. return fmt.Errorf("failed to delete device: %w", err)
  157. }
  158. m.logger.Info("Device deleted", zap.String("device_id", deviceID))
  159. return nil
  160. }
  161. // UpdateDeviceConfig 更新设备配置
  162. func (m *Manager) UpdateDeviceConfig(ctx context.Context, deviceID string, req *UpdateDeviceConfigRequest) error {
  163. var device Device
  164. // 查询设备
  165. if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
  166. if err == gorm.ErrRecordNotFound {
  167. return fmt.Errorf("device not found")
  168. }
  169. m.logger.Error("Failed to get device", zap.Error(err))
  170. return fmt.Errorf("failed to get device: %w", err)
  171. }
  172. // 更新配置
  173. device.Config = req.Config
  174. // 保存更新
  175. if err := m.db.WithContext(ctx).Save(&device).Error; err != nil {
  176. m.logger.Error("Failed to update device config", zap.Error(err))
  177. return fmt.Errorf("failed to update device config: %w", err)
  178. }
  179. // 创建配置更新事件
  180. event := &DeviceEvent{
  181. ID: generateEventID(),
  182. DeviceID: deviceID,
  183. Type: EventConfig,
  184. Severity: SeverityInfo,
  185. Message: "设备配置已更新",
  186. Timestamp: time.Now(),
  187. }
  188. if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
  189. m.logger.Error("Failed to create device event", zap.Error(err))
  190. }
  191. m.logger.Info("Device config updated", zap.String("device_id", deviceID))
  192. return nil
  193. }
  194. // UpdateFirmware 更新设备固件
  195. func (m *Manager) UpdateFirmware(ctx context.Context, deviceID string, req *UpdateFirmwareRequest) error {
  196. var device Device
  197. // 查询设备
  198. if err := m.db.WithContext(ctx).Where("id = ?", deviceID).First(&device).Error; err != nil {
  199. if err == gorm.ErrRecordNotFound {
  200. return fmt.Errorf("device not found")
  201. }
  202. m.logger.Error("Failed to get device", zap.Error(err))
  203. return fmt.Errorf("failed to get device: %w", err)
  204. }
  205. // 更新固件信息
  206. device.Firmware = FirmwareInfo{
  207. Version: req.Version,
  208. URL: req.URL,
  209. Description: req.Description,
  210. ReleaseDate: time.Now(),
  211. }
  212. // 更新设备状态为更新中
  213. device.Status = StatusUpdating
  214. // 保存更新
  215. if err := m.db.WithContext(ctx).Save(&device).Error; err != nil {
  216. m.logger.Error("Failed to update device firmware", zap.Error(err))
  217. return fmt.Errorf("failed to update device firmware: %w", err)
  218. }
  219. // 创建固件更新事件
  220. event := &DeviceEvent{
  221. ID: generateEventID(),
  222. DeviceID: deviceID,
  223. Type: EventFirmware,
  224. Severity: SeverityInfo,
  225. Message: fmt.Sprintf("固件更新开始,版本: %s", req.Version),
  226. Timestamp: time.Now(),
  227. }
  228. if err := m.db.WithContext(ctx).Create(event).Error; err != nil {
  229. m.logger.Error("Failed to create device event", zap.Error(err))
  230. }
  231. m.logger.Info("Device firmware update started",
  232. zap.String("device_id", deviceID),
  233. zap.String("version", req.Version))
  234. // TODO: 实际的固件更新逻辑
  235. // 这里应该通过协议适配器发送固件更新命令
  236. return nil
  237. }
  238. // StartStatusCheck 启动设备状态检查
  239. func (m *Manager) StartStatusCheck() {
  240. ticker := time.NewTicker(5 * time.Minute)
  241. defer ticker.Stop()
  242. for {
  243. select {
  244. case <-ticker.C:
  245. m.checkDeviceStatus()
  246. }
  247. }
  248. }
  249. // checkDeviceStatus 检查设备状态
  250. func (m *Manager) checkDeviceStatus() {
  251. ctx := context.Background()
  252. var devices []Device
  253. // 查询所有在线设备
  254. if err := m.db.WithContext(ctx).Where("status = ?", StatusOnline).Find(&devices).Error; err != nil {
  255. m.logger.Error("Failed to get online devices", zap.Error(err))
  256. return
  257. }
  258. // 检查每个设备的最后在线时间
  259. now := time.Now()
  260. for _, device := range devices {
  261. if device.LastSeen != nil && now.Sub(*device.LastSeen) > 10*time.Minute {
  262. // 设备离线
  263. device.Status = StatusOffline
  264. m.db.WithContext(ctx).Save(&device)
  265. // 创建离线事件
  266. event := &DeviceEvent{
  267. ID: generateEventID(),
  268. DeviceID: device.ID,
  269. Type: EventDisconnect,
  270. Severity: SeverityWarning,
  271. Message: "设备离线",
  272. Timestamp: now,
  273. }
  274. m.db.WithContext(ctx).Create(event)
  275. m.logger.Info("Device went offline", zap.String("device_id", device.ID))
  276. }
  277. }
  278. }
  279. // generateDeviceID 生成设备ID
  280. func generateDeviceID(deviceType string) string {
  281. return fmt.Sprintf("%s_%d", deviceType, time.Now().UnixNano())
  282. }
  283. // generateEventID 生成事件ID
  284. func generateEventID() string {
  285. return fmt.Sprintf("event_%d", time.Now().UnixNano())
  286. }