|
@@ -1,18 +1,20 @@
|
|
|
-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
|
|
|
{
|
|
@@ -22,197 +24,237 @@ namespace PRSServer
|
|
|
public DateTime TimeStamp { get; set; }
|
|
|
public CoreExpression<GPSBatteryFormulaModel, double>? BatteryFormula { get; set; }
|
|
|
|
|
|
- public Device(Guid id, DateTime timeStamp, CoreExpression<GPSBatteryFormulaModel, double>? batteryFormula)
|
|
|
+ public Device(Guid iD, DateTime timeStamp, CoreExpression<GPSBatteryFormulaModel, double>? batteryFormula)
|
|
|
{
|
|
|
- ID = id;
|
|
|
+ ID = iD;
|
|
|
TimeStamp = timeStamp;
|
|
|
BatteryFormula = batteryFormula;
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Should return a percentage
|
|
|
- /// </summary>
|
|
|
- /// <returns></returns>
|
|
|
public double CalculateBatteryLevel(double batteryValue)
|
|
|
{
|
|
|
- if (BatteryFormula != null)
|
|
|
+ if(BatteryFormula != null)
|
|
|
+ {
|
|
|
return BatteryFormula.Evaluate(new Dictionary<string, object?>
|
|
|
{
|
|
|
{ nameof(GPSBatteryFormulaModel.BatteryLevel), batteryValue }
|
|
|
});
|
|
|
+ }
|
|
|
return batteryValue;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// <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 GPSDeviceUpdate : ISerializeBinary
|
|
|
{
|
|
|
- /// <summary>
|
|
|
- /// Default Constants.
|
|
|
- /// </summary>
|
|
|
- public static IPAddress DEFAULT_SERVER = IPAddress.Any;
|
|
|
+ public string AuditTrail { get; set; }
|
|
|
|
|
|
- public static int DEFAULT_PORT = 7999;
|
|
|
+ public GPSTrackerLocation Location { get; set; }
|
|
|
|
|
|
- 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;
|
|
|
-
|
|
|
- private DateTime m_RefreshDate = DateTime.MinValue;
|
|
|
+ public void SerializeBinary(CoreBinaryWriter writer)
|
|
|
+ {
|
|
|
+ writer.Write(AuditTrail ?? "");
|
|
|
+ writer.WriteObject(Location);
|
|
|
+ }
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Local Variables Declaration.
|
|
|
- /// </summary>
|
|
|
- private TcpListener m_server;
|
|
|
+ public void DeserializeBinary(CoreBinaryReader reader)
|
|
|
+ {
|
|
|
+ AuditTrail = reader.ReadString();
|
|
|
+ Location = reader.ReadObject<GPSTrackerLocation>();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- private Task m_serverThread;
|
|
|
- private ArrayList m_socketListenersList;
|
|
|
- private bool m_stopPurging;
|
|
|
- private bool m_stopServer;
|
|
|
+ public class GPSUpdateQueue
|
|
|
+ {
|
|
|
+ public string QueuePath;
|
|
|
|
|
|
- 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)
|
|
|
+ /// <summary>
|
|
|
+ /// Get the first (earliest) items of the directory.
|
|
|
+ /// </summary>
|
|
|
+ /// <returns>A list of (filename, update) tuples.</returns>
|
|
|
+ public IEnumerable<Tuple<string, GPSDeviceUpdate>> GetFirstItems()
|
|
|
{
|
|
|
- Init(new IPEndPoint(serverIP, port));
|
|
|
+ var files = Directory.EnumerateFiles(QueuePath).OrderBy(x => x);
|
|
|
+
|
|
|
+ foreach (var filename in files)
|
|
|
+ {
|
|
|
+ GPSDeviceUpdate? deviceUpdate = null;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ using var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
|
|
|
+ deviceUpdate = Serialization.ReadBinary<GPSDeviceUpdate>(fileStream, BinarySerializationSettings.Latest);
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ // File is probably in use.
|
|
|
+ }
|
|
|
+ if(deviceUpdate is not null)
|
|
|
+ {
|
|
|
+ yield return new Tuple<string, GPSDeviceUpdate>(filename, deviceUpdate);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public GPSEngine(IPEndPoint ipNport)
|
|
|
+ public void QueueUpdate(GPSDeviceUpdate deviceUpdate)
|
|
|
{
|
|
|
- Init(ipNport);
|
|
|
+ var filename = Path.Combine(QueuePath, $"{DateTime.UtcNow.Ticks} - {deviceUpdate.Location.Tracker.ID}");
|
|
|
+
|
|
|
+ using var fileStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write);
|
|
|
+ Serialization.WriteBinary(deviceUpdate, fileStream, BinarySerializationSettings.Latest);
|
|
|
}
|
|
|
|
|
|
- ~GPSEngine()
|
|
|
+ public void QueueUpdate(string auditTrail, GPSTrackerLocation location) => QueueUpdate(new GPSDeviceUpdate
|
|
|
{
|
|
|
- Stop();
|
|
|
+ AuditTrail = auditTrail,
|
|
|
+ Location = location
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ internal class GPSDeviceCache : ConcurrentDictionary<string, Device>
|
|
|
+ {
|
|
|
+ public void Refresh()
|
|
|
+ {
|
|
|
+ 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))
|
|
|
+ sigfoxListener = new Listener<SigfoxHandler, SigfoxHandlerProperties>(new SigfoxHandlerProperties(DeviceCache, UpdateQueue));
|
|
|
+ sigfoxListener.InitPort((ushort)Properties.SigfoxListenPort);
|
|
|
+
|
|
|
+ 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();
|
|
|
+ }
|
|
|
+
|
|
|
+ // List of (filename, update)
|
|
|
+ private Queue<Tuple<string, GPSDeviceUpdate>> LocationQueueCache = new();
|
|
|
+
|
|
|
+ private void GetLocationQueue(int nLocations)
|
|
|
+ {
|
|
|
+ LocationQueueCache.EnsureCapacity(LocationQueueCache.Count + nLocations);
|
|
|
+ foreach(var item in UpdateQueue.GetFirstItems().Take(nLocations))
|
|
|
{
|
|
|
- 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);
|
|
|
- }
|
|
|
+ LocationQueueCache.Enqueue(item);
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
- public void StartSigfoxListener()
|
|
|
+ private void UpdateServer()
|
|
|
{
|
|
|
- if(Properties.SigfoxListenPort == 0)
|
|
|
+ // Cache a set of fifty, so that we're not running baack and forth to the filesystem all the time.
|
|
|
+ if(LocationQueueCache.Count == 0)
|
|
|
{
|
|
|
- Logger.Send(LogType.Information, "", "No Sigfox listen port specified\n");
|
|
|
- return;
|
|
|
+ GetLocationQueue(50);
|
|
|
}
|
|
|
|
|
|
- var listener = new Listener<SigfoxHandler, SigfoxHandlerProperties>(new SigfoxHandlerProperties(m_devices));
|
|
|
- listener.InitPort((ushort)Properties.SigfoxListenPort);
|
|
|
+ if (LocationQueueCache.Count > 0)
|
|
|
+ {
|
|
|
+ var (filename, update) = LocationQueueCache.Dequeue();
|
|
|
|
|
|
- Logger.Send(LogType.Information, "", "Starting Sigfox Listener on port " + Properties.SigfoxListenPort);
|
|
|
+ Logger.Send(LogType.Information, "",
|
|
|
+ string.Format("Updating Server ({0}): {1} - {2}", UpdateQueue.GetNumberOfItems(), update.Location.DeviceID, update.AuditTrail));
|
|
|
+ new Client<GPSTrackerLocation>().Save(update.Location, update.AuditTrail, (_, exception) =>
|
|
|
+ {
|
|
|
+ if (exception is not null)
|
|
|
+ {
|
|
|
+ Logger.Send(LogType.Error, "", $"Error saving GPS Tracker Location ({update.AuditTrail}): {CoreUtils.FormatException(exception)}");
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- listener.Start();
|
|
|
+ try
|
|
|
+ {
|
|
|
+ File.Delete(filename);
|
|
|
+ }
|
|
|
+ catch
|
|
|
+ {
|
|
|
+ // Probably got deleted.
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Method that starts TCP/IP Server.
|
|
|
- /// </summary>
|
|
|
public override void Run()
|
|
|
{
|
|
|
if (string.IsNullOrWhiteSpace(Properties.Server))
|
|
@@ -229,171 +271,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();
|
|
|
}
|
|
|
}
|
|
|
-}
|
|
|
+}
|