| 
					
				 | 
			
			
				@@ -1,218 +1,211 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using System.Collections; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using Comal.Classes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using InABox.Clients; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using InABox.Core; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using InABox.DigitalMatter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using InABox.IPC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using netDxf.Tables; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using PRSServer.Engines; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Collections.Concurrent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Collections.Generic; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Linq; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Net; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Net.Sockets; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using System.Threading; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Threading.Tasks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using Comal.Classes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using InABox.Clients; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using InABox.Core; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using InABox.DigitalMatter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using InABox.IPC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using PRSServer.Engines; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Timers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 namespace PRSServer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    internal class Device 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public class GPSDeviceUpdate : ISerializeBinary 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public Guid ID { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public DateTime TimeStamp { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public CoreExpression<GPSBatteryFormulaModel, double>? BatteryFormula { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public string AuditTrail { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public GPSTrackerLocation Location { get; set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public Device(Guid id, DateTime timeStamp, CoreExpression<GPSBatteryFormulaModel, double>? batteryFormula) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void SerializeBinary(CoreBinaryWriter writer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ID = id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            TimeStamp = timeStamp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            BatteryFormula = batteryFormula; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            writer.Write(AuditTrail ?? ""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            writer.WriteObject(Location); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// Should return a percentage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public double CalculateBatteryLevel(double batteryValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void DeserializeBinary(CoreBinaryReader reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (BatteryFormula != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return BatteryFormula.Evaluate(new Dictionary<string, object?> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { nameof(GPSBatteryFormulaModel.BatteryLevel), batteryValue } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return batteryValue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            AuditTrail = reader.ReadString(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Location = reader.ReadObject<GPSTrackerLocation>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ///     TCPServer is the Server class. When "StartServer" method is called 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ///     this Server object tries to connect to a IP Address specified on a port 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ///     configured. Then the server start listening for client socket requests. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ///     As soon as a requestcomes in from any client then a Client Socket 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ///     Listening thread will be started. That thread is responsible for client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ///     communication. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    internal class GPSEngine : Engine<GPSServerProperties> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public class GPSUpdateQueue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     Default Constants. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public static IPAddress DEFAULT_SERVER = IPAddress.Any; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public static int DEFAULT_PORT = 7999; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public static IPEndPoint DEFAULT_IP_END_POINT = new(DEFAULT_SERVER, DEFAULT_PORT); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly CancellationTokenSource cts = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly ConcurrentDictionary<string, Device> m_devices = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private Task m_purgingThread; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public string QueuePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private DateTime m_RefreshDate = DateTime.MinValue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     Local Variables Declaration. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private TcpListener m_server; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private Task m_serverThread; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private ArrayList m_socketListenersList; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private bool m_stopPurging; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private bool m_stopServer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly ConcurrentQueue<Tuple<GPSTrackerLocation, string>> m_updates = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private Task m_updatetask; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public GPSEngine() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public GPSUpdateQueue(string queuePath) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Init(DEFAULT_IP_END_POINT); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            QueuePath = queuePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public GPSEngine(IPAddress serverIP) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void InitQueueFolder() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Init(new IPEndPoint(serverIP, DEFAULT_PORT)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Directory.CreateDirectory(QueuePath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            catch (Exception e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new Exception($"Could not create directory for device update queue: {QueuePath}", e); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public GPSEngine(int port) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int GetNumberOfItems() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Init(new IPEndPoint(DEFAULT_SERVER, port)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Directory.EnumerateFiles(QueuePath).Count(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public GPSEngine(IPAddress serverIP, int port) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public IEnumerable<GPSDeviceUpdate> GetFirstItems() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Init(new IPEndPoint(serverIP, port)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var files = Directory.EnumerateFiles(QueuePath).OrderBy(x => x); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            foreach (var filename in files) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                GPSDeviceUpdate deviceUpdate; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    deviceUpdate = Serialization.ReadBinary<GPSDeviceUpdate>(fileStream, BinarySerializationSettings.Latest); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                yield return deviceUpdate; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public GPSEngine(IPEndPoint ipNport) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void QueueUpdate(GPSDeviceUpdate deviceUpdate) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Init(ipNport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var filename = $"{DateTime.UtcNow.Ticks} - {deviceUpdate.AuditTrail}: {deviceUpdate.Location.ID}"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            using var fileStream = new FileStream(filename, FileMode.CreateNew, FileAccess.Write); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Serialization.WriteBinary(deviceUpdate, fileStream, BinarySerializationSettings.Latest); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ~GPSEngine() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void QueueUpdate(string auditTrail, GPSTrackerLocation location) => QueueUpdate(new GPSDeviceUpdate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            AuditTrail = auditTrail, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Location = location 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    internal class GPSDeviceCache : ConcurrentDictionary<string, Device> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void Refresh() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.Send(LogType.Information, "", "Refreshing Tracker Cache"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var table = new Client<GPSTracker>().Query( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                new Columns<GPSTracker>(x => x.ID, x => x.DeviceID, x => x.Type.BatteryFormula)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.Send(LogType.Information, "", string.Format("- Tracker Cache: {0} devices", table.Rows.Count)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            foreach (var row in table.Rows) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var formula = row.Get<GPSTracker, string?>(x => x.Type.BatteryFormula); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var expression = string.IsNullOrWhiteSpace(formula) ? null : new CoreExpression<GPSBatteryFormulaModel, double>(formula); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                this[row.Get<GPSTracker, string>(x => x.DeviceID)] = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    new Device(row.Get<GPSTracker, Guid>(x => x.ID), DateTime.MinValue, expression); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public class GPSEngine : Engine<GPSServerProperties> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private Listener<SigfoxHandler, SigfoxHandlerProperties> sigfoxListener; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private OEMListener oemListener; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private GPSDeviceCache DeviceCache = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private Timer RefreshDevicesTimer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private Timer UpdateServerTimer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private GPSUpdateQueue UpdateQueue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public override void Configure(Server server) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             base.Configure(server); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            UpdateQueue = new GPSUpdateQueue(Path.Combine(AppDataFolder, "device_queue")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     Init method that create a server (TCP Listener) Object based on the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     IP Address and Port information that is passed in. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <param name="ipNport"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void Init(IPEndPoint ipNport) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void StartOEMListener() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_server = new TcpListener(ipNport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            catch (Exception e) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_server = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (Properties.ListenPort == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new Exception("Error: OEM Listen Port not Specified\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            m_updatetask = Task.Run(() => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                while (m_server != null && !cts.IsCancellationRequested) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (m_updates.Any()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        if (m_updates.TryDequeue(out var tuple)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            Logger.Send(LogType.Information, "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                string.Format("Updating Server ({0}): {1} - {2}", m_updates.Count, tuple.Item1.DeviceID, tuple.Item2)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new Client<GPSTrackerLocation>().Save(tuple.Item1, tuple.Item2, (_, __) => { }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            Thread.Sleep(Properties.UpdateTimer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }, cts.Token); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.Send(LogType.Information, "", "Starting OEM Listener on port " + Properties.ListenPort); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private static byte[] StringToByteArray(string hex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var NumberChars = hex.Length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var bytes = new byte[NumberChars / 2]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for (var i = 0; i < NumberChars; i += 2) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return bytes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            oemListener = new OEMListener(Properties.ListenPort, DeviceCache, UpdateQueue); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            oemListener.Start(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.Send(LogType.Information, "", "OEM Listener started on port " + Properties.ListenPort); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private bool CheckConnection() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void StartSigfoxListener() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (ClientFactory.UserGuid == Guid.Empty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (Properties.SigfoxListenPort == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Wait for server connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                while (!Client.Ping()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Logger.Send(LogType.Error, "", "Database server unavailable. Trying again in 30 seconds..."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Task.Delay(30_000).Wait(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    Logger.Send(LogType.Information, "", "Retrying connection..."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ClientFactory.SetBypass(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Logger.Send(LogType.Information, "", "No Sigfox listen port specified\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (DateTime.Now - m_RefreshDate > new TimeSpan(0, 5, 0)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Logger.Send(LogType.Information, "", "Refreshing Tracker Cache"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var table = new Client<GPSTracker>().Query( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    new Columns<GPSTracker>(x => x.ID, x => x.DeviceID, x => x.Type.BatteryFormula) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_RefreshDate = DateTime.Now; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Logger.Send(LogType.Information, "", string.Format("- Tracker Cache: {0} devices", table.Rows.Count)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_devices.Clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                foreach (var row in table.Rows) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var formula = row.Get<GPSTracker, string?>(x => x.Type.BatteryFormula); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var expression = string.IsNullOrWhiteSpace(formula) ? null : new CoreExpression<GPSBatteryFormulaModel, double>(formula); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    m_devices[row.Get<GPSTracker, string>(x => x.DeviceID)] = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        new Device(row.Get<GPSTracker, Guid>(x => x.ID), DateTime.MinValue, expression); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sigfoxListener = new Listener<SigfoxHandler, SigfoxHandlerProperties>(new SigfoxHandlerProperties(DeviceCache)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sigfoxListener.InitPort((ushort)Properties.SigfoxListenPort); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.Send(LogType.Information, "", "Starting Sigfox Listener on port " + Properties.SigfoxListenPort); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sigfoxListener.Start(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            Logger.Send(LogType.Information, "", "Sigfox Listener started on port " + Properties.SigfoxListenPort); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void StartUpdateServerTask() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            UpdateServerTimer = new Timer(Properties.UpdateTimer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            UpdateServerTimer.Elapsed += (o, e) => UpdateServer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            UpdateServerTimer.Start(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public void StartSigfoxListener() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private Queue<GPSDeviceUpdate> LocationQueueCache = new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void GetLocationQueue(int nLocations) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if(Properties.SigfoxListenPort == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            LocationQueueCache.EnsureCapacity(LocationQueueCache.Count + nLocations); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            foreach(var deviceUpdate in UpdateQueue.GetFirstItems().Take(50)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Logger.Send(LogType.Information, "", "No Sigfox listen port specified\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                LocationQueueCache.Enqueue(deviceUpdate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var listener = new Listener<SigfoxHandler, SigfoxHandlerProperties>(new SigfoxHandlerProperties(m_devices)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            listener.InitPort((ushort)Properties.SigfoxListenPort); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private void UpdateServer() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Cache a set of fifty, so that we're not running baack and forth to the filesystem all the time. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(LocationQueueCache.Count == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                GetLocationQueue(50); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Logger.Send(LogType.Information, "", "Starting Sigfox Listener on port " + Properties.SigfoxListenPort); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (LocationQueueCache.Count > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var last = LocationQueueCache.Dequeue(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            listener.Start(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Logger.Send(LogType.Information, "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    string.Format("Updating Server ({0}): {1} - {2}", UpdateQueue.GetNumberOfItems(), last.Location.DeviceID, last.AuditTrail)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                new Client<GPSTrackerLocation>().Save(last.Location, last.AuditTrail, (_, exception) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (exception is not null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        Logger.Send(LogType.Error, "", $"Error saving GPS Tracker Location ({last.AuditTrail}): {CoreUtils.FormatException(exception)}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     Method that starts TCP/IP Server. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public override void Run() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (string.IsNullOrWhiteSpace(Properties.Server)) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -229,171 +222,44 @@ namespace PRSServer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ClientFactory.SetClientType(typeof(IPCClient<>), Platform.GPSEngine, Version, DatabaseServerProperties.GetPipeName(Properties.Server)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             CheckConnection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            DMFactory.Initialise(Properties.DumpFormat, Properties.DumpFile); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            UpdateQueue.InitQueueFolder(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (m_server != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Create a ArrayList for storing SocketListeners before 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // starting the server. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_socketListenersList = new ArrayList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Start the Server and start the thread to listen client  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // requests. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_server.Start(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_serverThread = Task.Run(ServerThreadStart, cts.Token); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Create a low priority thread that checks and deletes client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // SocktConnection objcts that are marked for deletion. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_purgingThread = Task.Run(PurgingThreadStart, cts.Token); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Refresh device cache and set up timer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DeviceCache.Refresh(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RefreshDevicesTimer = new Timer(5 * 60 * 1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RefreshDevicesTimer.Elapsed += (o, e) => DeviceCache.Refresh(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RefreshDevicesTimer.Start(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DMFactory.Initialise(Properties.DumpFormat, Properties.DumpFile); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            StartOEMListener(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             StartSigfoxListener(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            StartUpdateServerTask(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     Method that stops the TCP/IP Server. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public override void Stop() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private bool CheckConnection() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (m_server != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (ClientFactory.UserGuid == Guid.Empty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // It is important to Stop the server first before doing 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // any cleanup. If not so, clients might being added as 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // server is running, but supporting data structures 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // (such as m_socketListenersList) are cleared. This might 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // cause exceptions. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                cts.Cancel(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Stop the TCP/IP Server. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_stopServer = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_server.Stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Wait for one second for the the thread to stop. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //m_serverThread.Join(1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // If still alive; Get rid of the thread. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //if (m_serverThread.IsAlive) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //   m_serverThread.Abort(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_serverThread = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_stopPurging = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //m_purgingThread.Join(1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //if (m_purgingThread.IsAlive) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //    m_purgingThread.Abort(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //m_purgingThread = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Free Server Object. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                m_server = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                while (m_updates.Any()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (m_updates.TryDequeue(out var tuple)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        Logger.Send(LogType.Information, "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            string.Format("Updating Server ({0}): {1} - {2}", m_updates.Count, tuple.Item1.DeviceID, tuple.Item2)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        new Client<GPSTrackerLocation>().Save(tuple.Item1, tuple.Item2, (_, __) => { }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        Thread.Sleep(2000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Stop All clients. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                StopAllSocketListers(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     Method that stops all clients and clears the list. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void StopAllSocketListers() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            foreach (GPSListener socketListener 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                     in m_socketListenersList) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                socketListener.StopSocketListener(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Remove all elements from the list. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            m_socketListenersList.Clear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            m_socketListenersList = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     TCP/IP Server Thread that is listening for clients. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void ServerThreadStart() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Client Socket variable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Socket clientSocket = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            GPSListener socketListener = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            while (!m_stopServer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (!CheckConnection()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // Wait for any client requests and if there is any  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // request from any client accept it (Wait indefinitely). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    clientSocket = m_server.AcceptSocket(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // Create a SocketListener object for the client. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    socketListener = new GPSListener(clientSocket, m_devices, m_updates); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // Add the socket listener to an array list in a thread  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // safe fashon. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    //Monitor.Enter(m_socketListenersList); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    lock (m_socketListenersList) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        m_socketListenersList.Add(socketListener); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    //Monitor.Exit(m_socketListenersList); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // Start a communicating with the client in a different 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // thread. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    socketListener.StartSocketListener(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                catch (SocketException se) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Wait for server connection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                while (!Client.Ping()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    m_stopServer = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Logger.Send(LogType.Error, "", "Database server unavailable. Trying again in 30 seconds..."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Task.Delay(30_000).Wait(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    Logger.Send(LogType.Information, "", "Retrying connection..."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ClientFactory.SetBypass(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     Thread method for purging Client Listeneres that are marked for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     deletion (i.e. clients with socket connection closed). This thead 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     is a low priority thread and sleeps for 10 seconds and then check 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     for any client SocketConnection obects which are obselete and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        ///     marked for deletion. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void PurgingThreadStart() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public override void Stop() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            while (!m_stopPurging) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var deleteList = new ArrayList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Check for any clients SocketListeners that are to be 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // deleted and put them in a separate list in a thread sage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // fashon. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //Monitor.Enter(m_socketListenersList); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                lock (m_socketListenersList) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    foreach (GPSListener socketListener 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             in m_socketListenersList) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        if (socketListener.IsMarkedForDeletion()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            deleteList.Add(socketListener); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            socketListener.StopSocketListener(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // Delete all the client SocketConnection ojects which are 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    // in marked for deletion and are in the delete list. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    for (var i = 0; i < deleteList.Count; ++i) m_socketListenersList.Remove(deleteList[i]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //Monitor.Exit(m_socketListenersList); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                deleteList = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                Thread.Sleep(10000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            oemListener.Stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sigfoxListener.Stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            UpdateServerTimer.Stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            RefreshDevicesTimer.Stop(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |