using System.Globalization; using Microsoft.EntityFrameworkCore; using RuleEngine.Common; using RuleEngine.Constants; using RuleEngine.Database; using RuleEngine.DTOs; using RuleEngine.Interfaces; using RuleEngine.Models; using RuleEngine.Requests; namespace RuleEngine.Services { public class DeviceService : IDeviceService { private readonly DatabaseContext _dbContext; private readonly IConfiguration _config; private readonly static string logFolderPath = LogConstants.LOG_FILE_PATH; private readonly static string exceptionFolder = LogConstants.LOG_EXCEPTION_FILE_PATH; private static readonly Dictionary> dictCarHistory = []; public DeviceService(DatabaseContext dbContext, IConfiguration config) { _dbContext = dbContext; _config = config; } public async Task UpdatePVT(DeviceMessage deviceMessage) { DeviceLogRequest? deviceLogRequest = null; try { var enableLogFile = _config.GetValue("EnableLogFile"); if (enableLogFile) { string Imei = ""; try { Imei = deviceMessage.Imei ?? string.Empty; } catch (Exception ex) { // Log the exception Console.WriteLine(ex.Message); } } deviceLogRequest = CreatePVTRequest(deviceMessage); if (deviceLogRequest == null) { return false; } if (deviceLogRequest.Code == "ERROR") { return false; } if (deviceLogRequest.GpsLat == 0 && deviceLogRequest.GpsLon == 0) { var online = _dbContext.Onlines.Where(x => (x.CarId ?? 0) == deviceLogRequest.CarID).FirstOrDefault(); if (online == null) { await UpdateOnlineProcedure(deviceLogRequest, deviceLogRequest.Imei); } else { if ((deviceLogRequest.GpsLat == 0) && (deviceLogRequest.GpsLon == 0)) { deviceLogRequest.GpsLat = online.GpsLat; deviceLogRequest.GpsLon = online.GpsLon; } //if ( (deviceLogRequest.NetworkLat == 0) && // (deviceLogRequest.NetworkLon == 0)) //{ // deviceLogRequest.NetworkLat = online.NetworkLat; // deviceLogRequest.NetworkLon = online.NetworkLon; //} await UpdateOnlineProcedure(deviceLogRequest, deviceLogRequest.Imei); } } else { await UpdateOnlineProcedure(deviceLogRequest, deviceLogRequest.Imei); } await InsertHistoryProcedure(deviceLogRequest, deviceLogRequest.Imei); } catch (Exception ex) { // Log the exception if (Directory.Exists(logFolderPath)) StaticResources.Log2File(logFolderPath + "PVTException.txt", ex.ToString()); return false; } return true; } private DeviceLogRequest? CreatePVTRequest(DeviceMessage deviceMessage, bool bReupPVT = false) { DeviceLogRequest? requestLog = null; var strServerTime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); string Imei = deviceMessage?.Imei ?? string.Empty; string strReceivedTime = deviceMessage?.ReceivedTime ?? string.Empty; DateTime receivedTime = DateTime.UtcNow; try { receivedTime = DateTime.ParseExact(strReceivedTime, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture); if (!string.IsNullOrEmpty(strReceivedTime)) { receivedTime = Convert.ToDateTime(strReceivedTime); } } catch (Exception ex) { StaticResources.Log2File(logFolderPath + "PVTException.txt", ex.ToString()); } if ((bReupPVT == true) && (Imei != null) && (Imei != "")) { if (!dictCarHistory.TryGetValue(Imei, out LimitedSizeQueue? queue)) { queue = new LimitedSizeQueue(QueueConstant.QUEUESIZE); dictCarHistory.Add(Imei, queue); } if (queue != null && !queue.Contains(receivedTime)) { queue.Enqueue(receivedTime); } else { return null; } } double longtitude = deviceMessage?.Longitude ?? 0; double latitude = deviceMessage?.Latitude ?? 0; int gpsSpeed = deviceMessage?.GpsSpeed ?? 0; bool isSos = deviceMessage?.IsSOS ?? false; bool isStrongBoxOpen = deviceMessage?.IsStrongBoxOpen ?? false; //co mo ket: dong/mo bool isEngineOn = deviceMessage?.IsEngineOn ?? false; //co dong co bat/tat bool isStopping = deviceMessage?.IsStopping ?? false; //co dung do dung/do bool isGPSLost = deviceMessage?.IsGPSLost ?? true; //co GPS mat/co int totalImageCam1 = deviceMessage?.TotalImgCam1 ?? 0; int totalImageCam2 = deviceMessage?.TotalImgCam2 ?? 0; string strRFID = deviceMessage?.StrRFID ?? string.Empty; string strOBD = deviceMessage?.StrOBD ?? string.Empty; string strLac = deviceMessage?.LacID ?? string.Empty; string version = deviceMessage?.Version ?? string.Empty; var gpsInfor = deviceMessage?.GpsInfor; bool isJamming = deviceMessage?.IsJamming ?? false; bool isSpoofing = deviceMessage?.IsSpoofing ?? false; bool cam1OK = deviceMessage?.Cam1OK ?? false; bool cam2OK = deviceMessage?.Cam2OK ?? false; bool camDetach = deviceMessage?.CamDetach ?? false; double cell_lat = 0; double cell_lon = 0; try { if (gpsInfor != null) { int cellid = gpsInfor.Cellid != null ? Convert.ToInt32(gpsInfor.Cellid) : 0; int lacid = gpsInfor.Lacid != null ? Convert.ToInt32(gpsInfor.Lacid) : 0; int mcc = gpsInfor.Mcc != null ? Convert.ToInt32(gpsInfor.Mcc) : 0; int mnc = gpsInfor.Mnc != null ? Convert.ToInt32(gpsInfor.Mnc) : 0; string strCellType = gpsInfor.NetworkType != null ? gpsInfor.NetworkType.Trim() : string.Empty; if ((cellid > 0) && (strCellType != null)) { strCellType = strCellType.ToLower(); int? CellTypeGoogle = 0; if (strCellType.Contains("cellsignalstrengthgsm")) CellTypeGoogle = 3; else if (strCellType.Contains("cellsignalstrengthcdma")) CellTypeGoogle = 2; else if (strCellType.Contains("cellsignalstrengthwcdma")) CellTypeGoogle = 1; else if (strCellType.Contains("cellsignalstrengthlte")) CellTypeGoogle = 0; var cellinfor = _dbContext.CellInfors.Where(x => (x.LacId == lacid) && (x.CellId == cellid) && (x.MCC == mcc) && (x.MNC == mnc) && (x.NetworkType == CellTypeGoogle) ).FirstOrDefault(); if (cellinfor == null) { if (CellTypeGoogle != null) { cellinfor = new CellInfor { CellId = cellid, LacId = lacid, MCC = mcc, MNC = mnc, NetworkType = CellTypeGoogle }; _dbContext.CellInfors.Add(cellinfor); _dbContext.SaveChanges(); } } else { cell_lat = cellinfor.NetworkLat ?? 0; cell_lon = cellinfor.NetworkLon ?? 0; if (cell_lat != 0 && cell_lon != 0 && latitude != 0 && longtitude != 0) { var dist = StaticResources.DistanceGpsCalculate(latitude, longtitude, cell_lat, cell_lon, 'K'); if (dist > DeviceConfig.SPOOFING_THRESH_DISTANCE) { isSpoofing = true; var strLog = string.Format($"{strServerTime} {Imei} {cellinfor.Id} {cellinfor.NetworkLat} {cellinfor.NetworkLon} {latitude} {longtitude} {dist}"); if (Directory.Exists(logFolderPath)) StaticResources.Log2File(logFolderPath + "SpoofingDetection.txt", strLog); } } } } } } catch (Exception ex) { if (Directory.Exists(logFolderPath)) StaticResources.Log2File(logFolderPath + "CELLException.txt", ex.ToString()); } return requestLog; } private async Task UpdateOnlineProcedure(DeviceLogRequest request, string imei) { try { DateTime currentTimeUTC = DateTime.UtcNow; DateTime localTime = currentTimeUTC.AddHours(7); if (request.ReceivedTime.Year <= (localTime.Year - 1)) //lost GPS { await UpdateLostGpsOnline(request.CarID, true, localTime); return; } // loc ban tin tuong lai TimeSpan diff02 = localTime.AddMinutes(5).Subtract(request.ReceivedTime); if (diff02.TotalSeconds > 0) // TotalSeconds < 0 - ban tin gui lai, ko cap nhat bang truc tuyen { await UpdateOnlines(request, localTime); } } catch (Exception ex) { StaticResources.LogException2File(exceptionFolder, imei + "_ex_pvt", DateTime.UtcNow.ToString() + " InsertLst_TrucTuyen " + ex.ToString()); } } private async Task UpdateOnlines(DeviceLogRequest request, DateTime localTime) { var isSos = request.IsSos == true; var isGpsLost = request.IsGPSLost == true; var strongBoxOpen = request.IsStrongBoxOpen == true; var engineOn = request.IsEngineOn == true; var carId = request.CarID; var deviceTime = request.ReceivedTime; var resetStatusMinute = DeviceConfig.SECONDS_SET_CAR_STOP / 60; var existingOnline = await _dbContext.Onlines .FindAsync(carId); if (existingOnline != null) { var diffSeconds = (deviceTime - existingOnline.DeviceTime)?.TotalSeconds ?? 0; if (diffSeconds <= 0) { // Device sent an older or duplicate message; do nothing return; } int carStatus = request.CarStatus ?? 0; if (diffSeconds > resetStatusMinute) { carStatus = 2; // timeout -> set as disconnected } // Update record existingOnline.GpsVelocity = request.GpsSpeed ?? 0; existingOnline.IsSos = isSos; existingOnline.IsGPSLost = isGpsLost; existingOnline.StrongBoxOpen = strongBoxOpen; existingOnline.EngineOn = engineOn; existingOnline.CarStatus = carStatus; existingOnline.Rfidstring = request.StrRFID; existingOnline.CellId = request.CellID; existingOnline.LacId = request.LacID ?? 0; existingOnline.GpsLat = request.GpsLat ?? 0; existingOnline.GpsLon = request.GpsLon ?? 0; existingOnline.NetworkLat = request.NetworkLat ?? 0; existingOnline.NetworkLon = request.NetworkLon ?? 0; existingOnline.IsJamming = request.IsJamming == true; existingOnline.IsSpoofing = request.IsSpoofing == true; existingOnline.IsCam1OK = request.Cam1OK == true; existingOnline.IsCam2OK = request.Cam2OK == true; existingOnline.GpsInfor = request.GPSInfor ?? ""; existingOnline.ReceivedTime = localTime; existingOnline.DeviceTime = deviceTime; existingOnline.AppVersion = request.Version; _dbContext.Onlines.Update(existingOnline); } else { // Insert new record var newOnline = new Online { CarId = carId, GpsVelocity = request.GpsSpeed ?? 0, IsSos = isSos, IsGPSLost = isGpsLost, StrongBoxOpen = strongBoxOpen, EngineOn = engineOn, CarStatus = request.CarStatus ?? 0, Rfidstring = request.StrRFID, CellId = request.CellID, LacId = request.LacID ?? 0, GpsLat = request.GpsLat ?? 0, GpsLon = request.GpsLon ?? 0, NetworkLat = request.NetworkLat ?? 0, NetworkLon = request.NetworkLon ?? 0, IsJamming = request.IsJamming == true, IsSpoofing = request.IsSpoofing == true, IsCam1OK = request.Cam1OK == true, IsCam2OK = request.Cam2OK == true, GpsInfor = request.GPSInfor ?? "", ReceivedTime = localTime, DeviceTime = deviceTime, AppVersion = request.Version }; await _dbContext.Onlines.AddAsync(newOnline); } await _dbContext.SaveChangesAsync(); } private async Task InsertHistoryProcedure(DeviceLogRequest request, string imei) { try { DateTime currentTimeUTC = DateTime.UtcNow; DateTime localTime = currentTimeUTC.AddHours(7); var history = new History { CarId = request.CarID, UnitId = request.UnitID, GpsVelocity = request.GpsSpeed ?? 0, IsSos = request.IsSos == true, IsGPSLost = request.IsGPSLost == true, StrongBoxOpen = request.IsStrongBoxOpen == true, EngineOn = request.IsEngineOn == true, CarStatus = request.CarStatus ?? 0, Rfidstring = request.StrRFID, GpsLat = request.GpsLat ?? 0, GpsLon = request.GpsLon ?? 0, GpsInfor = request.GPSInfor ?? string.Empty, IsJamming = request.IsJamming == true, IsSpoofing = request.IsSpoofing == true, Cam1OK = request.Cam1OK == true, Cam2OK = request.Cam2OK == true, CamDetach = request.CamDetach == true, ReceivedTime = localTime, DeviceTime = request.ReceivedTime, DeviceDate = int.Parse(request.ReceivedTime.ToString("yyyyMMdd")) }; await _dbContext.Histories.AddAsync(history); await _dbContext.SaveChangesAsync(); } catch (Exception ex) { StaticResources.LogException2File(exceptionFolder, imei + "_ex_pvt", DateTime.UtcNow.ToString() + " InsertHistoryProcedure " + ex.ToString()); } } public async Task UpdateLostGpsOnline(int carId, bool isGpsLost, DateTime receivedTime) { try { var online = await _dbContext.Onlines.FindAsync(carId); if (online != null) { online.IsGPSLost = isGpsLost; online.ReceivedTime = receivedTime; await _dbContext.SaveChangesAsync(); } } catch (Exception ex) { StaticResources.LogException2File(exceptionFolder, carId + "_ex_pvt", DateTime.UtcNow.ToString() + " UpdateLostGpsOnline " + ex.ToString()); } } } }