Procházet zdrojové kódy

设备断开连接和维护设备缓存

Jeremy před 3 roky
rodič
revize
55978f32ee

+ 2 - 0
AutoMapperProfile.cs

@@ -1,4 +1,5 @@
 using AutoMapper;
+using WingInterfaceLibrary.DTO.Device;
 using WingInterfaceLibrary.DTO.User;
 
 namespace WingDeviceService
@@ -8,6 +9,7 @@ namespace WingDeviceService
          public AutoMapperProfile()
          {
             CreateMap<UserDTO, UserPasswordDTO>().ReverseMap();
+            CreateMap<DeviceInfoDTO, CacheDeviceDTO>().ReverseMap();
          }
     }
 }

+ 84 - 0
Common/CacheManager.cs

@@ -0,0 +1,84 @@
+using System;
+using Newtonsoft.Json;
+using System.Globalization;
+using WingInterfaceLibrary.Enum;
+using System.Collections.Concurrent;
+
+namespace WingDeviceService.Common
+{
+    public class CacheManager<TObject> : IDisposable where TObject : class
+    {
+        private ConcurrentDictionary<string, TObject> _source = new();
+
+        /// <summary>
+        /// 添加/更新缓存
+        /// </summary>
+        /// <param name="key"></param>
+        /// <param name="obj"></param>
+        public TObject AddOrUpdate(string key, TObject obj)
+        {
+            return _source.AddOrUpdate(key, obj, (k, v) => obj);
+        }
+
+        /// <summary>
+        /// 删除缓存
+        /// </summary>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        public bool Remove(string key)
+        {
+            return _source.TryRemove(key, out _);
+        }
+
+        /// <summary>
+        /// 获取缓存信息
+        /// </summary>
+        /// <param name="key"></param>
+        /// <returns></returns>
+        public TObject Get(string key)
+        {
+            if (_source.TryGetValue(key, out TObject obj))
+            {
+                return obj;
+            }
+            return default;
+        }
+
+        /// <summary>
+        /// 清空缓存
+        /// </summary>
+        public void Dispose()
+        {
+            _source.Clear();
+        }
+    }
+
+    public class CacheManagerSingle<TObject> where TObject : class
+    {
+        private CacheManagerSingle() { }
+        private readonly static object _locker = new();
+        private static CacheManager<TObject> _instance;
+
+        /// <summary>
+        /// 单例对象
+        /// </summary>
+        /// <value></value>
+        public static CacheManager<TObject> Instance
+        {
+            get
+            {
+                if (_instance == null)
+                {
+                    lock (_locker)
+                    {
+                        if (_instance == null)
+                        {
+                            _instance = new CacheManager<TObject>();
+                        }
+                    }
+                }
+                return _instance;
+            }
+        }
+    }
+}

+ 191 - 21
Service/ConnectService.cs

@@ -1,12 +1,18 @@
 using System;
 using System.Threading.Tasks;
 using JsonRpcLite.Services;
+using WingDeviceService.Common;
+using WingInterfaceLibrary.DTO.Authentication;
 using WingInterfaceLibrary.DTO.Device;
+using WingInterfaceLibrary.Enum;
 using WingInterfaceLibrary.Interface;
+using WingInterfaceLibrary.Request;
 using WingInterfaceLibrary.Request.Authentication;
 using WingInterfaceLibrary.Request.Device;
 using WingInterfaceLibrary.Request.Notification;
 using WingInterfaceLibrary.Result.Device;
+using WingServerCommon.Log;
+using WingServerCommon.Mapper;
 using WingServerCommon.Service;
 
 namespace WingDeviceService.Service
@@ -16,11 +22,10 @@ namespace WingDeviceService.Service
     /// </summary>
     public partial class DeviceService : JsonRpcService, IConnectService
     {
-        private readonly object _createLocker = new object();
+        private readonly string _sourceUrl = "cloud.xinglinghui.com";
+        private readonly object _createShortCodeLocker = new object();
 
-        /// <summary>
-        /// 设备登录/注册
-        /// </summary>
+        /// <summary>设备连接云服务</summary>
         /// <param name="request">请求对象</param>
         /// <returns>授权响应</returns>
         /// <remarks>POST</remarks>        
@@ -66,10 +71,7 @@ namespace WingDeviceService.Service
                 var deviceCode = deviceDto?.DeviceCode;
                 if (string.IsNullOrWhiteSpace(shortCode))
                 {
-                    lock (_createLocker)
-                    {
-                        shortCode = GenerateShortCode();
-                    }
+                    shortCode = GenerateShortCode();
                 }
                 if (deviceDto == null)
                 {
@@ -112,8 +114,9 @@ namespace WingDeviceService.Service
                 {
                     Code = deviceCode,
                     IssueTime = now,
-                    SourceUrl = "cloud.xinglinghui.com",
+                    SourceUrl = _sourceUrl,
                 });
+                await SetDeviceOnlineAsync(deviceCode, true, true);
                 //注册通知
                 var subscribeNotifyRequest = new SubscribeNotifyRequest()
                 {
@@ -137,25 +140,192 @@ namespace WingDeviceService.Service
             }
         }
 
-        /// <summary>
-        /// 生成唯一 shortCode
-        /// </summary>
+        /// <summary>查询当前设备信息</summary>
+        /// <param name="request">请求对象</param>
+        /// <returns>设备信息</returns>
+        /// <remarks>POST</remarks>
+        public async Task<CacheDeviceDTO> GetDeviceByToken(TokenRequest request)
+        {
+            try
+            {
+                var deviceTokenDTO = await _authenticationServiceProxy.GetAuthToken(request);
+                if (deviceTokenDTO == null || string.IsNullOrWhiteSpace(deviceTokenDTO.Code))
+                {
+                    throw new RpcException(2004, "Permission validation error", "Permission validation error");
+                }
+                var cacheDeviceDTO = await GetDevice(deviceTokenDTO.Code);
+                if (cacheDeviceDTO == null)
+                {
+                    throw new RpcException(2004, "deviceInfo not find", "deviceInfo not find");
+                }
+                if (cacheDeviceDTO.LastLoginTime > deviceTokenDTO.IssueTime)
+                {
+                    throw new RpcException(20041, "Permission validation error", "Permission validation error");
+                }
+                await SetDeviceOnlineAsync(deviceTokenDTO.Code, true);
+                return cacheDeviceDTO;
+            }
+            catch (RpcException)
+            {
+                throw;
+            }
+            catch (Exception ex)
+            {
+                throw new RpcException(1001, ex.Message, ex.InnerException?.Message);
+            }
+        }
+
+        /// <summary>设备与云服务断开连接</summary>
+        /// <param name="request">请求对象</param>
+        /// <returns>是否成功</returns>
+        /// <value>true</value>
+        public async Task<bool> DisConnect(TokenRequest request)
+        {
+            try
+            {
+                var deviceTokenDTO = await _authenticationServiceProxy.GetAuthToken(request);
+                if (deviceTokenDTO == null || string.IsNullOrWhiteSpace(deviceTokenDTO.Code))
+                {
+                    Logger.WriteLineWarn($"DisConnect: invalid token");
+                }
+                var cacheDeviceDTO = await GetDevice(deviceTokenDTO.Code);
+                if (cacheDeviceDTO != null && cacheDeviceDTO.LastLoginTime <= deviceTokenDTO.IssueTime)
+                {
+                    if (await UpdateLastLoginTime(cacheDeviceDTO))
+                    {
+                        _cacheDeviceManager.Remove(cacheDeviceDTO.DeviceCode);
+                        Logger.WriteLineInfo($"DisConnect: device disconnect success.");
+                        return true;
+                    }
+                    else
+                    {
+                        throw new RpcException(20041, "disconnect error", "disconnect error");
+                    }
+                }
+                return true;
+            }
+            catch (RpcException)
+            {
+                throw;
+            }
+            catch (Exception ex)
+            {
+                throw new RpcException(1001, ex.Message, ex.InnerException?.Message);
+            }
+        }
+
+        /// <summary>生成唯一 shortCode</summary>
         /// <returns></returns>
         private string GenerateShortCode()
         {
-            var uniqueId = new byte[6];
-            var rand = new Random((int)(DateTime.Now.Ticks % 1000000));
-            for (int i = 0; i < 6; i++)
+            try
             {
-                int randCode;
-                do
+                lock (_createShortCodeLocker)
                 {
-                    randCode = rand.Next(50, 90);
-                    uniqueId[i] = Convert.ToByte(randCode);
-                } while (randCode >= 58 && randCode <= 64 || randCode == 79 || randCode == 73);
+                    var uniqueId = new byte[6];
+                    var rand = new Random((int)(DateTime.Now.Ticks % 1000000));
+                    for (int i = 0; i < 6; i++)
+                    {
+                        int randCode;
+                        do
+                        {
+                            randCode = rand.Next(50, 90);
+                            uniqueId[i] = Convert.ToByte(randCode);
+                        } while (randCode >= 58 && randCode <= 64 || randCode == 79 || randCode == 73);
+                    }
+
+                    return System.Text.Encoding.ASCII.GetString(uniqueId);
+                }
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLineError($"GenerateShortCode error {ex}");
             }
+            return string.Empty;
+        }
 
-            return System.Text.Encoding.ASCII.GetString(uniqueId);
+        /// <summary>查询设备信息</summary>
+        /// <param name="deviceCode"></param>
+        /// <returns></returns>
+        private async Task<CacheDeviceDTO> GetDevice(string deviceCode)
+        {
+            try
+            {
+                var cacheDTO = _cacheDeviceManager.Get(deviceCode);
+                if (cacheDTO == null)
+                {
+                    var deviceDTO = await _deviceInfoDBServiceProxy.FindDeviceInfoByCodeAsync(deviceCode);
+                    cacheDTO = deviceDTO.MappingTo<CacheDeviceDTO>();
+                    _cacheDeviceManager.AddOrUpdate(cacheDTO.DeviceCode, cacheDTO);
+                }
+                return cacheDTO;
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLineError($"GetDevice error {ex}");
+            }
+            return null;
         }
+
+        /// <summary>更新设备在线状态</summary>
+        /// <param name="deviceCode"></param>
+        /// <param name="isOnline"></param>
+        /// <param name="refresh"></param>
+        /// <returns></returns>
+        private async Task<CacheDeviceDTO> SetDeviceOnlineAsync(string deviceCode, bool isOnline, bool refresh = false)
+        {
+            try
+            {
+                var cacheDTO = _cacheDeviceManager.Get(deviceCode);
+                if (cacheDTO == null || refresh)
+                {
+                    var deviceDTO = await _deviceInfoDBServiceProxy.FindDeviceInfoByCodeAsync(deviceCode);
+                    cacheDTO = deviceDTO.MappingTo<CacheDeviceDTO>();
+                    cacheDTO.IsOnline = isOnline;
+                    cacheDTO.SourceUrl = _sourceUrl;
+                    _cacheDeviceManager.AddOrUpdate(cacheDTO.DeviceCode, cacheDTO);
+                }
+                else if (cacheDTO.IsOnline != isOnline)
+                {
+                    cacheDTO.IsOnline = isOnline;
+                    _cacheDeviceManager.AddOrUpdate(cacheDTO.DeviceCode, cacheDTO);
+                }
+                return cacheDTO;
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLineError($"SetDeviceOnlineAsync error {ex}");
+            }
+            return null;
+        }
+
+        private async Task<bool> UpdateLastLoginTime(DeviceInfoDTO deviceInfo)
+        {
+            try
+            {
+                var result = await _deviceInfoDBServiceProxy.UpdateLoginTimeAsync(new WingInterfaceLibrary.DB.Request.UpdateLoginTimeDBRequest
+                {
+                    DeviceCode = deviceInfo.DeviceCode,
+                    LastLoginTime = DateTime.UtcNow,
+                    ShortCode = deviceInfo.ShortCode,
+                    DeviceModel = deviceInfo.DeviceModel,
+                    DeviceType = deviceInfo.DeviceType,
+                    SoftwareVersion = deviceInfo.DeviceSoftwareVersion,
+                    SystemVersion = deviceInfo.SystemVersion,
+                    CPUModel = deviceInfo.CPUModel,
+                    Description = deviceInfo.Description,
+                    Name = deviceInfo.Name,
+                    OrganizationCode = deviceInfo.OrganizationCode,
+                    SystemLanguage = deviceInfo.SystemLanguage,
+                });
+                return result;
+            }
+            catch (Exception ex)
+            {
+                Logger.WriteLineError($"UpdateLastLoginTime err, {ex}");
+                return false;
+            }
+        }
+
     }
 }

+ 10 - 6
Service/DeviceService.cs

@@ -38,6 +38,14 @@ namespace WingDeviceService.Service
 
         private INotificationService _notificationService;
 
+        private CacheManager<CacheDeviceDTO> _cacheDeviceManager
+        {
+            get
+            {
+                return CacheManagerSingle<CacheDeviceDTO>.Instance;
+            }
+        }
+
         /// <summary>
         /// Init service
         /// </summary>
@@ -536,13 +544,9 @@ namespace WingDeviceService.Service
         /// <returns>服务器配置信息结果:key:字段,value:数据值,复杂类型可为json</returns>
         public async Task<Dictionary<string, string>> QueryServerConfig(TokenRequest request)
         {
-            var tokenInfo = await _authenticationServiceProxy.GetAuthToken(request);
-            if (tokenInfo == null)
-            {
-                throw new RpcException(1002, "Permission validation error", "Permission validation error");
-            }
+            var cacheDeviceDTO = await GetDeviceByToken(request);            
             //设备Code编码
-            var code = tokenInfo.Code;
+            var code = cacheDeviceDTO.DeviceCode;
             var dictionary = new Dictionary<string, string>();
             //定义配置字段 并扩充字段,返回数据可持续更新接口文档,如果数据是复杂类型可以转成json
             //TODO 配置信息: 直播配置、存储配置、

+ 1 - 1
WingDeviceService.csproj

@@ -7,7 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="WingInterfaceLibrary" Version="*" />
+    <PackageReference Include="WingInterfaceLibrary" Version="1.0.4.106-alpha" />
     <PackageReference Include="WingServerCommon" Version="*" />
   </ItemGroup>