1584 lines
68 KiB
C#
1584 lines
68 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using System.Threading;
|
|
using RegLibDLL;
|
|
using System.Diagnostics;
|
|
using SafeMobileLib;
|
|
using System.Runtime.InteropServices;
|
|
using System.Collections;
|
|
using System.Net.Mail;
|
|
using System.IO;
|
|
using SharedUI;
|
|
using SafeMobileLib.Helpers;
|
|
using System.IO.Pipes;
|
|
using System.Threading.Tasks;
|
|
using System.Timers;
|
|
using Newtonsoft.Json;
|
|
using SafeMobileLib.WebsocketClient;
|
|
using System.Data;
|
|
using System.ComponentModel;
|
|
|
|
namespace AppServer
|
|
{
|
|
public partial class MainForm : Form
|
|
{
|
|
private static Int64 DB_NUMBER_OF_INSERTS = 100000;
|
|
public static readonly short FEEDBACK_INTERACTION_WAIT_TIME_SEC = 7;
|
|
|
|
public static Boolean isRunning = true;
|
|
public static Boolean error = false;
|
|
private Int32 regPort = 5680;
|
|
private RegLib regLib;
|
|
private bool errorOnScreen = false;
|
|
private Int32 ErrorCount = 0;
|
|
public MainClass m = null;
|
|
public static Boolean withConsole = false;
|
|
public static String fileName = "";
|
|
DBregistrationManager regManager;
|
|
DBRadioTypeManager radioTypeManager;
|
|
DBvehiclesManager vehManager;
|
|
public static DBsettingsManager dbSettings;
|
|
public static bool IS_SIERRA_WIRELESS = false;
|
|
private DBsubsOperationManager dbsub;
|
|
public static InterthreadMessageQueue<string> LocationQueue;
|
|
public static InterthreadMessageQueue<string> prevLocationQueue;
|
|
public static InterthreadMessageQueue<UnitDataToSend> websocketLocationQueue;
|
|
public static InterthreadMessageQueue<MailMessage> ReportEmailQueue;///need to use this queue
|
|
public volatile static Hashtable VehListWithGroupDetails = new Hashtable();
|
|
public volatile static Hashtable VehList = new Hashtable();
|
|
public volatile static Hashtable userReportTimeList = new Hashtable();
|
|
public volatile static Hashtable VehStolen = new Hashtable();
|
|
public volatile static Hashtable VehicleHashStat = new Hashtable();
|
|
public volatile static Boolean AIRTURKEYLIMIT = false;
|
|
public volatile static UdpMulticast udp;
|
|
public static Boolean UdpMulticastConnectionStatus = false;
|
|
public static volatile bool ZonesBussy = false;
|
|
/// <summary>
|
|
/// hash table used for gateway statuses (message 500, 501, 503)
|
|
/// </summary>
|
|
internal static volatile Hashtable RadioGWHash = new Hashtable();
|
|
internal static Hashtable userStateHash = new Hashtable();
|
|
public volatile static Boolean SendPOLLafterSMS = false;
|
|
public volatile static Int32 CountInsert =0;
|
|
public volatile static Boolean RegistrationAnswer = false;
|
|
public static uint recordings = 0;
|
|
public static String GPS_Queue_File = "gps_queue.txt";
|
|
|
|
public static List<GatewayRegistration> allGateways = new List<GatewayRegistration>();
|
|
|
|
|
|
[DllImportAttribute("user32.dll")]
|
|
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
|
|
[DllImportAttribute("user32.dll")]
|
|
public static extern bool ReleaseCapture();
|
|
public const int WM_NCLBUTTONDOWN = 0xA1;
|
|
public const int HT_CAPTION = 0x2;
|
|
|
|
// background colors for each panel, they will change at runtime with ones from the UI
|
|
private Color softwareColor = Color.Teal;
|
|
private Color mapColor = Color.Crimson;
|
|
private Color featuresColor = Color.FromArgb(202,80,0);
|
|
|
|
// Type of panels with licenses
|
|
private enum LicensePanel { SOFTWARE, MAP, FEATURES };
|
|
private LicensePanel prevLicensePanel = LicensePanel.SOFTWARE;
|
|
public RADIOTYPE RadioType = RADIOTYPE.MOTO;
|
|
public static Int32 Job_ticking_count = 0;
|
|
public System.Timers.Timer gwCheckTimer = new System.Timers.Timer();
|
|
|
|
//Websocket
|
|
public static System.Timers.Timer sendWebsocketTimer = new System.Timers.Timer();
|
|
public static System.Timers.Timer checkWebsocketServerStatus = new System.Timers.Timer();
|
|
public static Boolean hasDBAccess;
|
|
public static String dbAccess;
|
|
private WebsocketThread websocket = null;
|
|
|
|
|
|
public delegate void UpdateLicensesUIInvokeCallBack();
|
|
public MainForm()
|
|
{
|
|
FireWallException fw = new FireWallException();
|
|
string name = System.AppDomain.CurrentDomain.FriendlyName;
|
|
string path = System.Windows.Forms.Application.ExecutablePath;
|
|
fw.checkFirewall(name, path);
|
|
|
|
//for loging
|
|
SM debug = new SM();
|
|
|
|
Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
|
Console.WriteLine("Version: " + v.ToString());
|
|
|
|
LocationQueue = new InterthreadMessageQueue<string>();
|
|
prevLocationQueue = new InterthreadMessageQueue<string>();
|
|
ReportEmailQueue = new InterthreadMessageQueue<MailMessage>();
|
|
websocketLocationQueue = new InterthreadMessageQueue<UnitDataToSend>();
|
|
|
|
|
|
gwCheckTimer.Elapsed += new ElapsedEventHandler(CheckGatewayStatus);
|
|
gwCheckTimer.Interval = 10000;
|
|
gwCheckTimer.Enabled = true;
|
|
|
|
sendWebsocketTimer.Elapsed += new ElapsedEventHandler(SendLocationToWebSocketHandler);
|
|
sendWebsocketTimer.Interval = Program.cfg.websocketTimer;
|
|
|
|
checkWebsocketServerStatus.Elapsed += new ElapsedEventHandler(BroadcastWebSocketStatusOnMessageBus);
|
|
checkWebsocketServerStatus.Interval = 5000;
|
|
|
|
|
|
//test id app is already running
|
|
bool shoulLoadThisOne = testIfAlreadyRunning();
|
|
|
|
// the test for application that is already running will return false only if the app
|
|
// already running but doesn't require to be closed, meaning this instance should be closed
|
|
if (!shoulLoadThisOne)
|
|
{
|
|
Program.SHOULD_LOAD = false;
|
|
}
|
|
// continue with loading this instance because no other one is running
|
|
else
|
|
ContinueConstructor();
|
|
|
|
Thread t = new Thread(HandleUnitStatus);
|
|
t.IsBackground = true;
|
|
t.Start();
|
|
|
|
}
|
|
|
|
|
|
private void ContinueConstructor()
|
|
{
|
|
InitializeComponent();
|
|
|
|
// customize the new FeedbackRadMessageBox
|
|
FeedbackRadMessageBox.InteractionWaitSeconds = FEEDBACK_INTERACTION_WAIT_TIME_SEC;
|
|
FeedbackRadMessageBox.SetTheme("TelerikMetroBlue");
|
|
|
|
// register for restart event
|
|
FeedbackRadMessageBox.OnRestartRequest += delegate ()
|
|
{
|
|
Utils.WriteLine("AppServer needs to be restarted", ConsoleColor.Cyan);
|
|
RestartApp();
|
|
};
|
|
|
|
String dongleError = "";
|
|
regLib = new RegLibDLL.RegLib();
|
|
RegStatus regStatus = RegStatus.UNKNOWN;
|
|
|
|
if (regLib.demoMode)
|
|
{
|
|
regStatus = RegStatus.VALID_DEMO;
|
|
SM.Debug("AppServer in demo mode: " + regLib.remainingTime() + " seconds remaining");
|
|
if (regLib.remainingTime() <= 1)
|
|
{
|
|
regStatus = RegStatus.DEMO_EXPIRED;
|
|
error = true;
|
|
}
|
|
Job_ticking_count = (regLib.jobTicketingCount() > 0 && regLib.jobTicketingCount() <= regLib.safeDispatchCount()) ? regLib.jobTicketingCount() : 0;
|
|
}
|
|
else
|
|
{
|
|
if (!regLib.dongleDetected())
|
|
{
|
|
regStatus = RegStatus.DONGLE_MISSING;
|
|
dongleError = "Dongle missing.";
|
|
error = true;
|
|
}
|
|
else
|
|
{
|
|
regStatus = RegStatus.VALID_DONGLE;
|
|
|
|
if (!regLib.validData())
|
|
{
|
|
dongleError = "No valid data found on dongle";
|
|
regStatus = RegStatus.DONGLE_NOT_INITIALIZED;
|
|
error = true;
|
|
}
|
|
else
|
|
{
|
|
if (!regLib.isCorrectHID())
|
|
{
|
|
regStatus = RegStatus.DONGLE_INVALID_HID;
|
|
dongleError = "Incorrect dongle HID";
|
|
error = true;
|
|
}
|
|
else
|
|
{
|
|
Job_ticking_count = (regLib.jobTicketingCount() > 0 && regLib.jobTicketingCount() <= regLib.safeDispatchCount()) ? regLib.jobTicketingCount() : 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
this.WindowState = FormWindowState.Minimized;
|
|
this.Visible = false;
|
|
notifyIcon1.Visible = true;
|
|
notifyIcon1.ShowBalloonTip(500);
|
|
try
|
|
{
|
|
Utils.WriteEventLog(Program.COMPANY, "AppServer ON", EventLogEntryType.Information, 3152);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Unable to write log Event ex:" + ex.ToString());
|
|
}
|
|
ContextMenu contextMenu = new ContextMenu();
|
|
contextMenu.MenuItems.Add("Check for updates...", (s, e) => {
|
|
UpdateForm uf = new UpdateForm(App.APP_SERVER, true) { IsDevelop = Program.cfg.isDevelop };
|
|
uf.Show();
|
|
});
|
|
contextMenu.MenuItems.Add("Exit", (s, e) => CloseApp());
|
|
notifyIcon1.ContextMenu = contextMenu;
|
|
|
|
|
|
if (!error)
|
|
{
|
|
m = new MainClass(this);
|
|
// gestion reset event
|
|
m.OnRefreshHashRequest += delegate()
|
|
{
|
|
ReportEmailQueue = new InterthreadMessageQueue<MailMessage>();
|
|
Thread.Sleep(500);
|
|
m.Start();
|
|
|
|
// update UI
|
|
this.Invoke((MethodInvoker)delegate()
|
|
{
|
|
UpdateLicensesUI();
|
|
});
|
|
|
|
};
|
|
|
|
regPort = Program.cfg.regPort;
|
|
//test if we can connect to DB
|
|
testDBconnection();
|
|
|
|
//start main class
|
|
m.Start();
|
|
|
|
|
|
LocationThread LocationConnection = new LocationThread();
|
|
Thread LocThreadObj = new Thread(new ThreadStart(LocationConnection.handleConnection));
|
|
LocThreadObj.IsBackground = true;
|
|
LocThreadObj.Start();
|
|
|
|
RegistrationThread RegistrationConnection = new RegistrationThread(regPort, Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user,
|
|
Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
|
|
Thread LocationThreadObj = new Thread(new ThreadStart(RegistrationConnection.handleConnection));
|
|
LocationThreadObj.IsBackground = true;
|
|
LocationThreadObj.Start();
|
|
}
|
|
else
|
|
{
|
|
String dialogMessage = "Invalid dongle. Please insert a valid dongle and restart the Application Server";
|
|
String dialogTitle = "Application Server Invalid Dongle";
|
|
// display other messages based on the error type
|
|
switch(regStatus)
|
|
{
|
|
case RegStatus.DEMO_EXPIRED:
|
|
{
|
|
dialogMessage = $"Your demo period had expired. Please contact {Program.COMPANY} if you want to extend it.";
|
|
dialogTitle = "Application Server Demo Expired";
|
|
break;
|
|
}
|
|
case RegStatus.DONGLE_INVALID_HID:
|
|
{
|
|
dialogMessage = $"Your dongle has an invalid HID value. Please contact {Program.COMPANY} in order to reconfigure the dongle.";
|
|
dialogTitle = "Application Server Dongle Invalid HID";
|
|
break;
|
|
}
|
|
case RegStatus.DONGLE_MISSING:
|
|
{
|
|
dialogMessage = $"Your dongle is missing. Please connect the dongle if not connected, or change the port if already connected. Then restart Application Server.";
|
|
dialogTitle = "Application Server Dongle Missing";
|
|
break;
|
|
}
|
|
case RegStatus.DONGLE_NOT_INITIALIZED:
|
|
{
|
|
dialogMessage = $"Your dongle is not initialized or contains invalid data. Please contact {Program.COMPANY} in order to reconfigure the dongle.";
|
|
dialogTitle = "Application Server Demo Expired";
|
|
break;
|
|
}
|
|
}
|
|
|
|
FeedbackRadMessageBox.InteractionWaitSeconds = 15;
|
|
FeedbackRadMessageBox.ShowError(dialogMessage, dialogTitle);
|
|
FeedbackRadMessageBox.InteractionWaitSeconds = FEEDBACK_INTERACTION_WAIT_TIME_SEC;
|
|
Environment.Exit(0);
|
|
}
|
|
// update UI
|
|
|
|
UpdateLicensesUI();
|
|
//set DB Access Licence
|
|
dbAccess = regLib.dbAccessCount().ToString();
|
|
MainForm.hasDBAccess = (dbAccess.Equals("1") ? true : false);
|
|
Utils.WriteLine("3rd Party API WebSocket: " + hasDBAccess.ToString());
|
|
|
|
if (hasDBAccess)
|
|
{
|
|
ThreadStart action = () => {
|
|
ConfigureWebSocket();
|
|
};
|
|
Thread thread = new Thread(action) { IsBackground = true };
|
|
thread.Start();
|
|
}
|
|
|
|
softwareColor = circularUnits.ProgressCircleColor;
|
|
mapColor = circularGoogle.ProgressCircleColor;
|
|
featuresColor = circularLive.ProgressCircleColor;
|
|
|
|
// change the active panel in order to color the circular menus
|
|
ChangeFocusedLicensesGroup(LicensePanel.SOFTWARE);
|
|
|
|
}
|
|
|
|
|
|
private void ConfigureWebSocket()
|
|
{
|
|
if (!checkWebsocketServerStatus.Enabled)
|
|
checkWebsocketServerStatus.Enabled = true;
|
|
|
|
if (!sendWebsocketTimer.Enabled)
|
|
sendWebsocketTimer.Enabled = true;
|
|
|
|
BackgroundWorker webSocketWorker = new BackgroundWorker();
|
|
|
|
websocket = WebsocketThread.Instance;
|
|
websocket.host = Program.cfg.websocketUrl;
|
|
Utils.WriteLine("Setting 3rd Party API WebSocket host: " + Program.cfg.websocketUrl, ConsoleColor.Yellow);
|
|
|
|
//websocket.StartWebsocket();
|
|
|
|
webSocketWorker.DoWork += websocket.StartWebsocket;
|
|
webSocketWorker.RunWorkerAsync();
|
|
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restart the application and close other notify icons
|
|
/// </summary>
|
|
public void RestartApp()
|
|
{
|
|
CloseNotifyIcon();
|
|
|
|
Program.isRunning = false;
|
|
|
|
Thread p = new Thread(new ThreadStart(delegate ()
|
|
{
|
|
Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location, String.Join(" ", Program.cmdArgs));
|
|
|
|
CloseApp();
|
|
|
|
}));
|
|
p.Start();
|
|
|
|
}
|
|
|
|
private void CloseApp()
|
|
{
|
|
Process oldProcess = Process.GetCurrentProcess();
|
|
oldProcess.Kill();
|
|
Application.Exit();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Hide the notify icon method. This will cause the right bottom icon to be hide
|
|
/// </summary>
|
|
private void CloseNotifyIcon()
|
|
{
|
|
if (notifyIcon1 != null)
|
|
{
|
|
notifyIcon1.Visible = false;
|
|
notifyIcon1.Icon = null;
|
|
notifyIcon1.Dispose();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private string get_radio_type()
|
|
{
|
|
string radio_type = string.Empty;
|
|
|
|
// if radio_type isn't saved in db => check folder's name
|
|
System.IO.DirectoryInfo myDirectory = new DirectoryInfo(Environment.CurrentDirectory);
|
|
// get parent directory
|
|
string parentDirectory = myDirectory.Parent.FullName;
|
|
DirectoryInfo dInfo = new DirectoryInfo(parentDirectory);
|
|
DirectoryInfo[] subdirs = dInfo.GetDirectories();
|
|
foreach (DirectoryInfo folder in subdirs)
|
|
{
|
|
if (folder.Name == "Gateway") { radio_type = ((int)RADIOTYPE.MOTO).ToString(); break; }
|
|
else if (folder.Name == "Hytera") { radio_type = ((int)RADIOTYPE.HYT).ToString(); break; }
|
|
else if (folder.Name == "Momentum") { radio_type = ((int)RADIOTYPE.HARRIS).ToString(); break; }
|
|
else if (folder.Name == "Astro") { radio_type = ((int)RADIOTYPE.ATLAS).ToString(); break; }
|
|
else if (folder.Name == "Tetra") { radio_type = ((int)RADIOTYPE.TETRA).ToString(); break; }
|
|
else if (folder.Name == "Connect Plus") { radio_type = ((int)RADIOTYPE.CONECTPLUS).ToString(); break; }
|
|
else if (folder.Name == "Repeater_Gateway") { radio_type = ((int)RADIOTYPE.REPEATER_TRBO).ToString(); break; }
|
|
else if (folder.Name == "SMC_Gateway") { radio_type = ((int)RADIOTYPE.MOTO).ToString(); break; }
|
|
else if (folder.Name == "Simoco") { radio_type = ((int)RADIOTYPE.SIMOCO).ToString(); break; }
|
|
else if (folder.Name == "Sepura3T_SDR") { radio_type = ((int)RADIOTYPE.LISF).ToString(); break; }
|
|
}
|
|
|
|
return radio_type;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the UI licenses circular controllers. This will read the dongle licenses
|
|
/// and the ones from the DB and the display them in the UI.
|
|
/// </summary>
|
|
private void UpdateLicensesUI()
|
|
{
|
|
Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
|
String[] appname = this.Text.Split(" ".ToCharArray());
|
|
this.Text = appname[0] + " " + v.ToString();
|
|
lbVersion.Text = "Version " + v.ToString();
|
|
|
|
//check radio type from database to set job ticketing to visible
|
|
if (Program.cfg == null)
|
|
return;
|
|
|
|
radioTypeManager = new DBRadioTypeManager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
dbSettings = new DBsettingsManager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
|
|
string radio_type = radioTypeManager.getRadioType();
|
|
if(radio_type == "")
|
|
{
|
|
|
|
radio_type = get_radio_type();
|
|
//save radiotype in db
|
|
radioTypeManager.setRadioType(radio_type);
|
|
}
|
|
|
|
if (radio_type != "")
|
|
RadioType = (RADIOTYPE)Enum.Parse(typeof(RADIOTYPE), radio_type);
|
|
|
|
lbLicTicketing.Visible = circularTicketing.Visible = pbTicketing.Visible = labelTicketing.Visible = (RadioType == RADIOTYPE.MOTO || RadioType == RADIOTYPE.REPEATER_TRBO);
|
|
lbLicTelemetry.Visible = circularTelemetry.Visible = pbTicketing.Visible = labelTelemetry.Visible
|
|
= (RadioType == RADIOTYPE.MOTO || RadioType == RADIOTYPE.REPEATER_TRBO || RadioType == RADIOTYPE.HYT || RadioType == RADIOTYPE.HARRIS);
|
|
|
|
|
|
circularSDM.Visible = pbSDM.Visible = labelSDM.Visible = lbLicSDM.Visible = (RadioType == RADIOTYPE.SIMOCO);
|
|
|
|
// change logo icon depending on the system type
|
|
pbLogo.Image = (RadioType == RADIOTYPE.SIMOCO) ? AppServer.Properties.Resources.simoco :
|
|
AppServer.Properties.Resources.safemobile;
|
|
|
|
if (error)
|
|
{
|
|
if (regLib.demoMode)
|
|
{
|
|
lbRegistrationStatus.Text = (regLib.remainingTime() == 1) ? "Demo invalidated, please contact " + Program.COMPANY : "Demo registration expired"; ;
|
|
lbRegistrationStatus.ForeColor = Color.DarkRed;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
if (regLib.demoMode)
|
|
{
|
|
lbRegistrationStatus.Text = "trial ends in " + (regLib.remainingTime() / 86400).ToString() + " days ";
|
|
lbRegistrationStatus.ForeColor = Color.Yellow;
|
|
}
|
|
|
|
regManager = new DBregistrationManager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
vehManager = new DBvehiclesManager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
dbsub = new DBsubsOperationManager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
|
|
uint gpsCount = regManager.getGPSCount();
|
|
uint smsCount = regManager.getSMSCount();
|
|
uint reportsCount = regManager.getReportsCount();
|
|
uint voiceCount = regManager.getVoiceCount();
|
|
uint zonesCount = regManager.getZonesCount();
|
|
uint telemetryCount = regManager.getTelemetryCount();
|
|
uint GoogleCount = regManager.getGoogleCount();
|
|
uint MapUSCount = regManager.getMapsUSCount();
|
|
uint OSMCount = regManager.getOSMCount();
|
|
uint ArcgisCount = regManager.getMapsArcgisCount();
|
|
allGateways = regManager.getAllGateways();
|
|
int gatewaysCount = allGateways.Count();
|
|
uint ticketingCount = regManager.getTicketingCount();
|
|
uint recordingsCount = recordings = regManager.getRecordingsCount();
|
|
int allSDCount = regManager.getAllSafeDispatches().Count();
|
|
|
|
#region VALUES
|
|
int nrOfUnits = regLib.getNumberOfUnits();
|
|
// detect if Sierra Wireless
|
|
IS_SIERRA_WIRELESS = dbsub.IsSierraWireless();
|
|
int totaldbunits = 0;
|
|
uint nrOfUnitsInDB = (uint)vehManager.getActiveVehiclesCount(nrOfUnits,IS_SIERRA_WIRELESS, out totaldbunits);
|
|
circularUnits.MinValue = (nrOfUnits > 0) ? 0 : -1;
|
|
circularUnits.MaxValue = regLib.getNumberOfUnits();
|
|
circularUnits.Value = (nrOfUnitsInDB > circularUnits.MaxValue
|
|
? circularUnits.MaxValue : nrOfUnitsInDB);
|
|
lbLicUnits.Text = circularUnits.Value + " of " + circularUnits.MaxValue;
|
|
|
|
int nrSD = regLib.safeDispatchCount();
|
|
circularSD.MinValue = (nrSD > 0) ? 0 : -1;
|
|
circularSD.MaxValue = regLib.safeDispatchCount();
|
|
circularSD.Value = (allSDCount > circularSD.MaxValue
|
|
? circularSD.MaxValue : allSDCount);
|
|
lbLicSD.Text = circularSD.Value + " of " + circularSD.MaxValue;
|
|
|
|
|
|
int sdmCount = regLib.SDMobileCount();
|
|
circularSDM.MinValue = (sdmCount > 0 && sdmCount <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularSDM.MaxValue = ((sdmCount > regLib.safeDispatchCount()) ? 0 : sdmCount);
|
|
circularSDM.Value = 0;
|
|
lbLicSDM.Text = circularSDM.Value + " of " + circularSDM.MaxValue;
|
|
|
|
int nrGateways = regLib.gatewayCount();
|
|
circularGateways.MinValue = (nrGateways > 0 && nrGateways <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularGateways.MaxValue = regLib.gatewayCount();
|
|
circularGateways.Value = (gatewaysCount > circularGateways.MaxValue
|
|
? circularGateways.MaxValue : gatewaysCount);
|
|
lbLicGateways.Text = circularGateways.Value + " of " + circularGateways.MaxValue;
|
|
|
|
// set values for maps licenses
|
|
int nrGoogle = regLib.mapType1Count();
|
|
circularGoogle.MinValue = (nrGoogle > 0 && nrGoogle <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularGoogle.MaxValue = regLib.mapType1Count();
|
|
circularGoogle.Value = (GoogleCount > circularGoogle.MaxValue
|
|
? circularGoogle.MaxValue : GoogleCount);
|
|
lbLicGoogle.Text = circularGoogle.Value + " of " + circularGoogle.MaxValue;
|
|
|
|
int nrArcGis = regLib.mapType4Count();
|
|
circularArcGis.MinValue = (nrArcGis > 0 && nrArcGis <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularArcGis.MaxValue = regLib.mapType4Count();
|
|
circularArcGis.Value = (ArcgisCount > circularArcGis.MaxValue
|
|
? circularArcGis.MaxValue : ArcgisCount);
|
|
lbLicArcGis.Text = circularArcGis.Value + " of " + circularArcGis.MaxValue;
|
|
|
|
int nrOSM = regLib.mapType3Count();
|
|
circularOSM.MinValue = (nrOSM > 0 && nrOSM <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularOSM.MaxValue = regLib.mapType3Count();
|
|
circularOSM.Value = (OSMCount > circularOSM.MaxValue
|
|
? circularOSM.MaxValue : OSMCount);
|
|
lbLicOSM.Text = circularOSM.Value + " of " + circularOSM.MaxValue;
|
|
|
|
// set values for features licenses
|
|
int nrGPS = regLib.gpsCount();
|
|
circularLive.MinValue = (nrGPS > 0 && nrGPS <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularLive.MaxValue = regLib.gpsCount();
|
|
circularLive.Value = (gpsCount > circularLive.MaxValue
|
|
? circularLive.MaxValue : gpsCount);
|
|
lbLicLive.Text = circularLive.Value + " of " + circularLive.MaxValue;
|
|
|
|
|
|
int nrVoice = regLib.voiceCount();
|
|
circularVoice.MinValue = (nrVoice > 0 && nrVoice <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
//circularVoice.MaxValue = ((nrVoice > regLib.safeDispatchCount()) ? 0 : nrVoice);
|
|
circularVoice.MaxValue = regLib.voiceCount();
|
|
|
|
uint nrOfVoice = regManager.getVoiceCount();
|
|
circularVoice.Value = (nrOfVoice > circularVoice.MaxValue ?
|
|
circularVoice.MaxValue : nrOfVoice);
|
|
lbLicVoice.Text = circularVoice.Value + " of " + circularVoice.MaxValue;
|
|
|
|
int nrText = regLib.smsCount();
|
|
circularText.MinValue = (nrText > 0 && nrText <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularText.MaxValue = regLib.smsCount();
|
|
circularText.Value = (smsCount > circularText.MaxValue
|
|
? circularText.MaxValue : smsCount);
|
|
lbLicText.Text = circularText.Value + " of " + circularText.MaxValue;
|
|
|
|
|
|
int nrTicketing = regLib.jobTicketingCount();
|
|
circularTicketing.MinValue = (nrTicketing > 0 && nrTicketing <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
//circularTicketing.MaxValue = ((nrTicketing > regLib.safeDispatchCount()) ? 0 : nrTicketing);
|
|
circularTicketing.MaxValue = regLib.jobTicketingCount();
|
|
circularTicketing.Value = (ticketingCount > circularTicketing.MaxValue
|
|
? circularTicketing.MaxValue : ticketingCount);
|
|
lbLicTicketing.Text = circularTicketing.Value + " of " + circularTicketing.MaxValue;
|
|
|
|
|
|
int nrReports = regLib.reportsCount();
|
|
circularReports.MinValue = (nrReports > 0 && nrReports <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularReports.MaxValue = nrReports;
|
|
circularReports.Value = (reportsCount > circularReports.MaxValue
|
|
? circularReports.MaxValue : reportsCount);
|
|
lbLicReports.Text = circularReports.Value + " of " + circularReports.MaxValue;
|
|
|
|
|
|
int nrZones = regLib.zonesCount();
|
|
circularZones.MinValue = (nrZones > 0 && nrZones <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularZones.MaxValue = nrZones;
|
|
circularZones.Value = (zonesCount > circularZones.MaxValue
|
|
? circularZones.MaxValue : zonesCount);
|
|
lbLicEmail.Text = circularZones.Value + " of " + circularZones.MaxValue;
|
|
|
|
|
|
int nrTelem = regLib.telemetryCount();
|
|
circularTelemetry.MinValue = (nrTelem > 0 && nrTelem <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularTelemetry.MaxValue = regLib.telemetryCount();
|
|
circularTelemetry.Value = (telemetryCount > circularTelemetry.MaxValue
|
|
? circularTelemetry.MaxValue : telemetryCount);
|
|
lbLicTelemetry.Text = circularTelemetry.Value + " of " + circularTelemetry.MaxValue;
|
|
|
|
int nrRecordings = regLib.recordingsCount();
|
|
circularRecordings.MinValue = (nrRecordings > 0 && nrRecordings <= regLib.safeDispatchCount()) ? 0 : -1;
|
|
circularRecordings.MaxValue = regLib.recordingsCount();
|
|
circularRecordings.Value = (recordingsCount > circularRecordings.MaxValue
|
|
? circularRecordings.MaxValue : recordingsCount);
|
|
lbLicRecordings.Text = circularRecordings.Value + " of " + circularRecordings.MaxValue;
|
|
|
|
#endregion
|
|
|
|
if (regLib.AIRTURKEYLIMIT)
|
|
{
|
|
AIRTURKEYLIMIT = true;
|
|
lbRegistrationRemaining.Text = "Demo 1.10.2014 - 1.05.2015";
|
|
}
|
|
|
|
if (gpsCount > regLib.gpsCount() || smsCount > regLib.smsCount() || reportsCount > regLib.reportsCount()
|
|
|| voiceCount > regLib.voiceCount() || zonesCount > regLib.zonesCount()
|
|
|| telemetryCount > regLib.telemetryCount()
|
|
|| GoogleCount > regLib.mapType1Count() || MapUSCount > regLib.mapType2Count()
|
|
|| OSMCount > regLib.mapType3Count() || ArcgisCount > regLib.mapType4Count()
|
|
|| ticketingCount > regLib.jobTicketingCount() || recordingsCount > regLib.recordingsCount())
|
|
{
|
|
regManager.resetSafeDispatchRegistrations();
|
|
lbRegistrationRemaining.Text = "Database licenses reset";
|
|
}
|
|
|
|
if(gatewaysCount > regLib.gatewayCount())
|
|
regManager.removeAllGatewayRegistrations();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Intercept mouse move on all the items of the form
|
|
/// </summary>
|
|
/// <param name="sender">UI object which raised the event</param>
|
|
/// <param name="e">Mouse event parameters</param>
|
|
private void MainForm_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
// move form window if mouse moved with mouse pressed
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
ReleaseCapture();
|
|
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
|
|
}
|
|
|
|
// get mouse position relative to the form
|
|
var relativePoint = this.PointToClient(Cursor.Position);
|
|
|
|
|
|
// detect which panel is active
|
|
LicensePanel panel = LicensePanel.SOFTWARE;
|
|
if(relativePoint.Y >= dividerFeature.Location.Y)
|
|
panel = LicensePanel.FEATURES;
|
|
else if (relativePoint.Y > dividerMap.Location.Y)
|
|
panel = LicensePanel.MAP;
|
|
else
|
|
panel = LicensePanel.SOFTWARE;
|
|
|
|
|
|
// change UI only if prev panel is different
|
|
if (panel != prevLicensePanel)
|
|
{
|
|
// change the focused licenses panel
|
|
ChangeFocusedLicensesGroup(panel);
|
|
}
|
|
|
|
// save previous panel
|
|
prevLicensePanel = panel;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Change the circle color according to the mouse position and the
|
|
/// focused panel of licenses
|
|
/// </summary>
|
|
/// <param name="panel">The corresponding panel which is active</param>
|
|
private void ChangeFocusedLicensesGroup(LicensePanel panel)
|
|
{
|
|
foreach(Control ctrl in this.Controls)
|
|
{
|
|
if(ctrl is CircularProgressBar.CircularProgressBar)
|
|
{
|
|
CircularProgressBar.CircularProgressBar circular = (CircularProgressBar.CircularProgressBar)ctrl;
|
|
circular.ProgressCircleColor = Color.DarkGray;
|
|
circular.InnerCircleColor = Color.DarkGray;
|
|
circular.OuterCircleColor = Color.DarkGray;
|
|
}
|
|
}
|
|
dividerSoftware.BackColor = Color.DarkGray;
|
|
dividerMap.BackColor = Color.DarkGray;
|
|
dividerFeature.BackColor = Color.DarkGray;
|
|
lbFeatureLicenses.ForeColor = Color.DarkGray;
|
|
lbMapLicenses.ForeColor = Color.DarkGray;
|
|
lbSoftwareLicenses.ForeColor = Color.DarkGray;
|
|
lbSoftwareLicenses.Text = "Software Licenses";
|
|
lbMapLicenses.Text = "Map Licenses";
|
|
lbFeatureLicenses.Text = "Feature Licenses";
|
|
pbFeatureLicenses.Image = Properties.Resources.feature;
|
|
pbSoftwareLicenses.Image = Properties.Resources.software;
|
|
pbMapLicenses.Image = Properties.Resources.maps;
|
|
|
|
// detect panel lower and higher Y coordinates
|
|
int minY = 0, maxY = 0;
|
|
Color toPrintColor = softwareColor;
|
|
switch (panel)
|
|
{
|
|
case LicensePanel.SOFTWARE:
|
|
{
|
|
// get panel coordinates and color in which needs to be printed
|
|
toPrintColor = softwareColor;
|
|
dividerSoftware.BackColor = softwareColor;
|
|
lbSoftwareLicenses.ForeColor = Color.FromArgb(211, 211, 211);
|
|
pbSoftwareLicenses.Image = Properties.Resources.software_over;
|
|
lbSoftwareLicenses.Text = "Software Licenses";
|
|
minY = 0;
|
|
maxY = dividerMap.Location.Y;
|
|
break;
|
|
}
|
|
case LicensePanel.MAP:
|
|
{
|
|
// get panel coordinates and color in which needs to be printed
|
|
toPrintColor = mapColor;
|
|
lbMapLicenses.ForeColor = Color.FromArgb(211, 211, 211);
|
|
pbMapLicenses.Image = Properties.Resources.maps_over;
|
|
dividerMap.BackColor = mapColor;
|
|
lbMapLicenses.Text = "Map Licenses";
|
|
minY = dividerMap.Location.Y;
|
|
maxY = dividerFeature.Location.Y;
|
|
break;
|
|
}
|
|
case LicensePanel.FEATURES:
|
|
{
|
|
// get panel coordinates and color in which needs to be printed
|
|
toPrintColor = featuresColor;
|
|
dividerFeature.BackColor = featuresColor;
|
|
lbFeatureLicenses.ForeColor = Color.FromArgb(211, 211, 211);
|
|
pbFeatureLicenses.Image = Properties.Resources.feature_over;
|
|
lbFeatureLicenses.Text = "Feature Licenses";
|
|
minY = dividerFeature.Location.Y;
|
|
maxY = 1000;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
foreach (Control ctrl in this.Controls)
|
|
{
|
|
if (ctrl is CircularProgressBar.CircularProgressBar)
|
|
{
|
|
CircularProgressBar.CircularProgressBar circular = (CircularProgressBar.CircularProgressBar)ctrl;
|
|
|
|
if (circular.Location.Y >= minY && circular.Location.Y < maxY)
|
|
{
|
|
circular.ProgressCircleColor = toPrintColor;
|
|
circular.InnerCircleColor = toPrintColor;
|
|
circular.OuterCircleColor = toPrintColor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void notifyIcon1_DoubleClick(object sender, EventArgs e)
|
|
{
|
|
this.Visible = true;
|
|
this.WindowState = FormWindowState.Normal;
|
|
notifyIcon1.Visible = false;
|
|
}
|
|
|
|
private void MainForm_Resize(object sender, EventArgs e)
|
|
{
|
|
if (this.WindowState == FormWindowState.Minimized)
|
|
{
|
|
this.Visible = false;
|
|
notifyIcon1.Visible = true;
|
|
}
|
|
}
|
|
|
|
private void MainForm_Load(object sender, EventArgs e)
|
|
{
|
|
LoadLocationQueueFromFile();
|
|
|
|
|
|
gwCheckTimer.Start();
|
|
|
|
#region SOFTWARE LICENSES
|
|
circularUnits.Controls.Add(labelUnits);
|
|
labelUnits.Location = new Point(29, 63);
|
|
labelUnits.BackColor = Color.Transparent;
|
|
circularUnits.Controls.Add(pbUnits);
|
|
pbUnits.Location = new Point(26, 14);
|
|
pbUnits.BackColor = Color.Transparent;
|
|
|
|
|
|
circularSD.Controls.Add(labelSD);
|
|
labelSD.Location = new Point(23, 63);
|
|
labelSD.BackColor = Color.Transparent;
|
|
circularSD.Controls.Add(pbSD);
|
|
pbSD.Location = new Point(26, 16);
|
|
pbSD.BackColor = Color.Transparent;
|
|
|
|
|
|
circularGateways.Controls.Add(labelGateways);
|
|
labelGateways.Location = new Point(23, 63);
|
|
labelGateways.BackColor = Color.Transparent;
|
|
circularGateways.Controls.Add(pbGateways);
|
|
pbGateways.Location = new Point(27, 16);
|
|
pbGateways.BackColor = Color.Transparent;
|
|
|
|
|
|
circularSDM.Controls.Add(labelSDM);
|
|
labelSDM.Location = new Point(22, 63);
|
|
labelSDM.BackColor = Color.Transparent;
|
|
circularSDM.Controls.Add(pbSDM);
|
|
pbSDM.Location = new Point(31, 21);
|
|
pbSDM.BackColor = Color.Transparent;
|
|
#endregion
|
|
|
|
|
|
#region MAPS
|
|
circularGoogle.Controls.Add(labelGoogle);
|
|
labelGoogle.Location = new Point(20, 63);
|
|
labelGoogle.BackColor = Color.Transparent;
|
|
circularGoogle.Controls.Add(pbGoogle);
|
|
pbGoogle.Location = new Point(27, 16);
|
|
pbGoogle.BackColor = Color.Transparent;
|
|
|
|
|
|
circularArcGis.Controls.Add(pbArcGis);
|
|
pbArcGis.Location = new Point(29, 21);
|
|
pbArcGis.BackColor = Color.Transparent;
|
|
circularArcGis.Controls.Add(labelArcGis);
|
|
labelArcGis.Location = new Point(25, 63);
|
|
labelArcGis.BackColor = Color.Transparent;
|
|
|
|
circularOSM.Controls.Add(pbOSM);
|
|
pbOSM.Location = new Point(29, 21);
|
|
pbOSM.BackColor = Color.Transparent;
|
|
circularOSM.Controls.Add(labelOSM);
|
|
labelOSM.Location = new Point(25, 63);
|
|
labelOSM.BackColor = Color.Transparent;
|
|
#endregion
|
|
|
|
|
|
#region FEATURE LICENSES
|
|
circularLive.Controls.Add(pbLive);
|
|
pbLive.Location = new Point(29, 21);
|
|
pbLive.BackColor = Color.Transparent;
|
|
circularLive.Controls.Add(labelLive);
|
|
labelLive.Location = new Point(24, 63);
|
|
labelLive.BackColor = Color.Transparent;
|
|
|
|
circularVoice.Controls.Add(pbVoice);
|
|
pbVoice.Location = new Point(29, 21);
|
|
pbVoice.BackColor = Color.Transparent;
|
|
circularVoice.Controls.Add(labelVoice);
|
|
labelVoice.Location = new Point(24, 63);
|
|
labelVoice.BackColor = Color.Transparent;
|
|
|
|
|
|
circularText.Controls.Add(pbText);
|
|
pbText.Location = new Point(29, 21);
|
|
pbText.BackColor = Color.Transparent;
|
|
circularText.Controls.Add(labelText);
|
|
labelText.Location = new Point(24, 63);
|
|
labelText.BackColor = Color.Transparent;
|
|
|
|
circularTicketing.Controls.Add(pbTicketing);
|
|
pbTicketing.Location = new Point(29, 21);
|
|
pbTicketing.BackColor = Color.Transparent;
|
|
circularTicketing.Controls.Add(labelTicketing);
|
|
labelTicketing.Location = new Point(24, 63);
|
|
labelTicketing.BackColor = Color.Transparent;
|
|
|
|
circularReports.Controls.Add(pbReports);
|
|
pbReports.Location = new Point(31, 21);
|
|
pbReports.BackColor = Color.Transparent;
|
|
circularReports.Controls.Add(labelReports);
|
|
labelReports.Location = new Point(24, 63);
|
|
labelReports.BackColor = Color.Transparent;
|
|
|
|
circularZones.Controls.Add(pbZones);
|
|
pbZones.Location = new Point(29, 21);
|
|
pbZones.BackColor = Color.Transparent;
|
|
circularZones.Controls.Add(labelZones);
|
|
labelZones.Location = new Point(22, 63);
|
|
labelZones.BackColor = Color.Transparent;
|
|
|
|
circularTelemetry.Controls.Add(pbTelemetry);
|
|
pbTelemetry.Location = new Point(27, 21);
|
|
pbTelemetry.BackColor = Color.Transparent;
|
|
circularTelemetry.Controls.Add(labelTelemetry);
|
|
labelTelemetry.Location = new Point(21, 63);
|
|
labelTelemetry.BackColor = Color.Transparent;
|
|
|
|
circularRecordings.Controls.Add(pbRecordings);
|
|
pbRecordings.Location = new Point(29, 21);
|
|
pbRecordings.BackColor = Color.Transparent;
|
|
circularRecordings.Controls.Add(labelRecordings);
|
|
labelRecordings.Location = new Point(24, 63);
|
|
labelRecordings.BackColor = Color.Transparent;
|
|
#endregion
|
|
|
|
if (!error)
|
|
{
|
|
this.Visible = false;
|
|
}
|
|
|
|
if(udp != null)
|
|
{
|
|
byte[] heartbeatMsg = SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#507#");
|
|
udp.Send(heartbeatMsg, heartbeatMsg.Length);
|
|
}
|
|
|
|
// check for a new version if available
|
|
if(Program.cfg.autoupdate)
|
|
CheckForUpdate();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Test if the App Server is already running
|
|
/// </summary>
|
|
private bool testIfAlreadyRunning()
|
|
{
|
|
Process[] processlist = Process.GetProcesses();
|
|
Process curentP = Process.GetCurrentProcess();
|
|
int count = 0;
|
|
foreach (Process theprocess in processlist)
|
|
{
|
|
if (theprocess.ProcessName == curentP.ProcessName)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
if (count > 1)
|
|
{
|
|
SM.Debug("App already running!!!");
|
|
|
|
foreach (Process theprocess in processlist)
|
|
{
|
|
if (theprocess.ProcessName == curentP.ProcessName)
|
|
{
|
|
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
|
|
Console.WriteLine("Curent Process: {0} ID: {1}", curentP.ProcessName, curentP.Id);
|
|
if (theprocess.Id != curentP.Id)
|
|
{
|
|
Console.WriteLine("Killing Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
|
|
try
|
|
{
|
|
theprocess.Kill();
|
|
}
|
|
catch (NotSupportedException)
|
|
{
|
|
Utils.WriteLine("Process already killed!", ConsoleColor.Yellow);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.WriteLine("Fatal error!\n" + ex.ToString(), ConsoleColor.Red);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Thread.Sleep(1000);
|
|
|
|
return true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void testDBconnection()
|
|
{
|
|
DBmanager DB = new DBmanager(Program.cfg.DB_IP, Program.cfg.DB_schema, Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
try
|
|
{
|
|
DB.InitConnection();
|
|
DB.CloseConnection();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug(ex.ToString());
|
|
FeedbackRadMessageBox.ShowError("DB connection failed!!!Please check database settings and restart appServer!!!", "AppServer - Database Error");
|
|
try
|
|
{
|
|
Utils.WriteEventLog(Program.COMPANY, "AppServer OFF test DB connection", EventLogEntryType.Information, 3152);
|
|
}
|
|
catch (Exception exe)
|
|
{
|
|
SM.Debug("Unable to write log Event ex:" + exe.ToString());
|
|
}
|
|
try
|
|
{
|
|
DB.CloseConnection();
|
|
DB.InitConnection();
|
|
}
|
|
catch (Exception exe)
|
|
{
|
|
try
|
|
{
|
|
udp.Send(SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#210#4#AppServer stoped#"), SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#210#4#AppServer stoped#").Length);
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
SM.Debug("Error on sending Message to SD that APPServer has problem: " + ex2.ToString());
|
|
}
|
|
SM.Debug(exe.ToString());
|
|
notifyIcon1.Dispose();
|
|
|
|
// remove timers and other UI stuffs
|
|
MainForm_FormClosing(this, null);
|
|
// kill AppServer process
|
|
CloseApp();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
private int heartbeatWaitStep = 0;
|
|
private void Check_dongle_timer_Tick(object sender, EventArgs e)
|
|
{
|
|
if (udp == null)
|
|
return;
|
|
// increment at each 1000 ms tick of the timer
|
|
heartbeatWaitStep++;
|
|
|
|
// send heartbeat message if step is larger than number of seconds
|
|
if(heartbeatWaitStep >= SafeMobileLib.Modules.AppServerMonitoring.APP_SERVER_HEARTBEAT_SEC)
|
|
{
|
|
byte[] heartbeatMsg = SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#507#");
|
|
udp.Send(heartbeatMsg, heartbeatMsg.Length);
|
|
|
|
heartbeatWaitStep = 0;
|
|
}
|
|
|
|
|
|
if (!regLib.findDongle() && !errorOnScreen)
|
|
{
|
|
if (!regLib.demoMode)
|
|
{
|
|
ErrorCount++;
|
|
if (ErrorCount > 10)
|
|
{
|
|
errorOnScreen = true;
|
|
error = true;
|
|
try
|
|
{
|
|
udp.Send(SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#210#2#Dongle missing Application server stopped#"), SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#210#2#Dongle missing Application server stopped#").Length);
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
SM.Debug("Error on sending Message to SD that APPServer has problem: " + ex2.ToString());
|
|
}
|
|
try
|
|
{
|
|
Utils.WriteEventLog(Program.COMPANY, "AppServer OFF Dongle missing", EventLogEntryType.Information, 3152);
|
|
}
|
|
catch (Exception exe)
|
|
{
|
|
SM.Debug("Unable to write log Event ex:" + exe.ToString());
|
|
}
|
|
|
|
String dialogMessage = "Invalid dongle. Please insert a valid dongle and restart the Application Server";
|
|
String dialogTitle = "Application Server Invalid Dongle";
|
|
|
|
FeedbackRadMessageBox.InteractionWaitSeconds = 60;
|
|
FeedbackRadMessageBox.ShowError(dialogMessage, dialogTitle);
|
|
FeedbackRadMessageBox.InteractionWaitSeconds = FEEDBACK_INTERACTION_WAIT_TIME_SEC;
|
|
// remove timers and other UI stuffs
|
|
MainForm_FormClosing(this, null);
|
|
// kill AppServer process
|
|
CloseApp();
|
|
}
|
|
}
|
|
}
|
|
else ErrorCount = 0;
|
|
|
|
if (CountInsert > DB_NUMBER_OF_INSERTS)// 50000) //100000
|
|
{
|
|
Utils.WriteLine("Insert number is " + CountInsert, ConsoleColor.Cyan);
|
|
|
|
// dump the gps queue to a file
|
|
// TODO
|
|
|
|
ProcessTick();
|
|
}
|
|
}
|
|
|
|
public static void LoadLocationQueueFromFile()
|
|
{
|
|
// restore location queue
|
|
if (File.Exists(GPS_Queue_File))
|
|
{
|
|
// empty the previous queue file
|
|
prevLocationQueue.Clear();
|
|
|
|
List<String> prevGpsMessages = SerializationHelper.DesirializeWithLinq(GPS_Queue_File);
|
|
prevLocationQueue.PostItems(prevGpsMessages);
|
|
|
|
Utils.WriteLine($"Loaded {prevGpsMessages.Count} positions from offline cached file", ConsoleColor.Yellow);
|
|
|
|
try
|
|
{
|
|
File.Delete(GPS_Queue_File);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// unable to delete previous queue file
|
|
Utils.WriteLine("Exception when deleting previous gps queue file : " + ex.ToString(), ConsoleColor.Red);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public static void DumpLocationQueueToFile()
|
|
{
|
|
// write location queue to a file
|
|
if (MainForm.LocationQueue.Count > 0 || MainForm.prevLocationQueue.Count > 0)
|
|
{
|
|
|
|
List<string> allPositions = MainForm.LocationQueue.ToList();
|
|
allPositions.AddRange(MainForm.prevLocationQueue.ToList());
|
|
|
|
SerializationHelper.SerializeWithLinq(allPositions, GPS_Queue_File);
|
|
Utils.WriteLine($"Wrote {allPositions.Count} GPS messages from the queue into a file", ConsoleColor.Yellow);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populate the Websocket Location Queue and call the timer method to send the data
|
|
/// </summary>
|
|
/// <param name="radioID"></param>
|
|
/// <param name="lat"></param>
|
|
/// <param name="lng"></param>
|
|
/// <param name="speed"></param>
|
|
/// <param name="unit_time"></param>
|
|
public static void CheckLocationQueueAndSendToWebSocket(string radioID, double lat, double lng, int speed, uint unit_time,
|
|
String heading, Status_for_tab status)
|
|
{
|
|
|
|
Int64 radioId = 0;
|
|
bool parseResult = Int64.TryParse(radioID.Trim(), out radioId);
|
|
|
|
// skip any unit that is not
|
|
if(parseResult && radioId < 12000 && radioId > 12999)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UnitDataToSend data = new UnitDataToSend();
|
|
data.radio_id = radioID;
|
|
data.lat = lat;
|
|
data.lng = lng;
|
|
data.speed = speed;
|
|
data.unix_time = unit_time;
|
|
|
|
|
|
if(VehListWithGroupDetails.ContainsKey(radioID))
|
|
data.GroupName = ((Vehicles)VehListWithGroupDetails[radioID]).GroupName;
|
|
|
|
data.Heading = heading;
|
|
data.GpsState = status.ToString();
|
|
|
|
// get group name for the radioId
|
|
|
|
|
|
MainForm.websocketLocationQueue.PostItem(data);
|
|
if(!sendWebsocketTimer.Enabled)
|
|
sendWebsocketTimer.Enabled = true;
|
|
if (!checkWebsocketServerStatus.Enabled)
|
|
checkWebsocketServerStatus.Enabled = true;
|
|
}
|
|
|
|
|
|
private void BroadcastWebSocketStatusOnMessageBus(object source, ElapsedEventArgs e)
|
|
{
|
|
//string message; //$"#0.0#{failoverStatusToMessBuss}#{configHelper.PCIp}#{msg}#{master}#";
|
|
|
|
string status = "offline";
|
|
IWebsocketClient iWebsocketClient = WebsocketThread.Instance.getClient();
|
|
if( iWebsocketClient != null)
|
|
status = iWebsocketClient.IsRunning ? "online" : "offline";
|
|
|
|
string message = $"#0.0#{Utils.enumConvertToString(MessageBusCmds.WebsocketStatusToMsgBus)}#{status}#";
|
|
|
|
byte[] dataToSend = Utils.Convert_text_For_multicast(message);
|
|
|
|
if(dataToSend != null && dataToSend.Length > 0)
|
|
udp.Send(dataToSend, dataToSend.Length);
|
|
|
|
}
|
|
|
|
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
// stop the dongle timer
|
|
Check_dongle_timer?.Stop();
|
|
|
|
//stop gatewaycheck
|
|
gwCheckTimer.Stop();
|
|
sendWebsocketTimer.Stop();
|
|
checkWebsocketServerStatus.Stop();
|
|
WebsocketThread._client?.Dispose();
|
|
|
|
// save all unhandled gps positions
|
|
DumpLocationQueueToFile();
|
|
if(Program.cfg.watchdog)
|
|
Program.KillWatchDog();
|
|
|
|
try
|
|
{
|
|
CloseNotifyIcon();
|
|
|
|
Utils.WriteEventLog(Program.COMPANY, "AppServer OFF on close", EventLogEntryType.Information, 3152);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Unable to write log Event ex:" + ex.ToString());
|
|
}
|
|
try
|
|
{
|
|
udp.Send(Utils.Convert_text_For_multicast($"#0.0#{Utils.enumConvertToString(MessageBusCmds.WebsocketStatusToMsgBus)}#offline#"),
|
|
Utils.Convert_text_For_multicast($"#0.0#{Utils.enumConvertToString(MessageBusCmds.WebsocketStatusToMsgBus)}#offline#").Length);
|
|
udp.Send(Utils.Convert_text_For_multicast("#0.0#210#4#Application server stopped#"),
|
|
Utils.Convert_text_For_multicast("#0.0#210#4#Application server stopped#").Length);
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
SM.Debug("Error on sending Message to SD that APPServer has problem: " + ex2.ToString());
|
|
}
|
|
|
|
isRunning = false;
|
|
}
|
|
|
|
public void ProcessTick()
|
|
{
|
|
try
|
|
{
|
|
try
|
|
{
|
|
udp.Send(SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#210#5#Application server restart#"), SafeMobileLib.Utils.Convert_text_For_multicast("#0.0#210#5#Application server restart#").Length);
|
|
}
|
|
catch (Exception ex2)
|
|
{
|
|
SM.Debug("Error on sending Message to SD that APPServer has problem: " + ex2.ToString());
|
|
}
|
|
finally
|
|
{
|
|
RestartApp();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SM.Debug("Error on restart timer:" + ex.ToString());
|
|
// the process did not exist - probably already closed!
|
|
//TODO: --> LOG
|
|
}
|
|
}
|
|
|
|
|
|
private void pictClose_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
pictClose.Image = global::AppServer.Properties.Resources.close_over;
|
|
this.Cursor = Cursors.Hand;
|
|
}
|
|
|
|
private void pictClose_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
pictClose.Image = global::AppServer.Properties.Resources.close;
|
|
this.Cursor = Cursors.Arrow;
|
|
}
|
|
|
|
private void pictClose_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
this.Close();
|
|
Process oldProcess = Process.GetCurrentProcess();
|
|
oldProcess.Kill();
|
|
System.Windows.Forms.Application.Exit();
|
|
}
|
|
|
|
private void pictMin_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
pictMin.Image = global::AppServer.Properties.Resources.minimize_over;
|
|
this.Cursor = Cursors.Hand;
|
|
}
|
|
|
|
private void pictMin_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
pictMin.Image = global::AppServer.Properties.Resources.minimize;
|
|
this.Cursor = Cursors.Arrow;
|
|
}
|
|
|
|
private void pictMin_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
this.WindowState = FormWindowState.Minimized;
|
|
}
|
|
private void StartReport_Tick(object sender, EventArgs e)
|
|
{
|
|
foreach (DictionaryEntry item in userReportTimeList)
|
|
{
|
|
if (!((UserReportTime)item.Value).ReportExecuted)
|
|
{
|
|
if ((DateTime.Now.Hour == ((UserReportTime)item.Value).HH && (DateTime.Now.Minute == ((UserReportTime)item.Value).MM)))
|
|
{
|
|
((UserReportTime)item.Value).ReportExecuted = true;
|
|
Process notePad = new Process();
|
|
notePad.StartInfo.FileName = "ReportstoEmail.exe";
|
|
notePad.StartInfo.Arguments = ((UserReportTime)item.Value).UserID.ToString().Trim() + " " + ((UserReportTime)item.Value).UserName.Trim();
|
|
notePad.Start();
|
|
}
|
|
}
|
|
// put ReportExecuted on false 1 minute before event fired
|
|
if ((DateTime.Now.Hour == ((UserReportTime)item.Value).HH && (DateTime.Now.Minute == ((UserReportTime)item.Value).MM -1 )))
|
|
((UserReportTime)item.Value).ReportExecuted = false;
|
|
}
|
|
}
|
|
|
|
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
if (notifyIcon1 != null)
|
|
{
|
|
notifyIcon1.Dispose();
|
|
}
|
|
}
|
|
//for ARS DB thread
|
|
public void HandleUnitStatus()
|
|
{
|
|
Thread.Sleep(500);
|
|
|
|
Utils.WriteLine("HandleUnitStatus thread...");
|
|
int count = 0;
|
|
DBsubsOperationManager dbsubsoperManage = new DBsubsOperationManager(Program.cfg.DB_IP, Program.cfg.DB_schema,
|
|
Program.cfg.DB_user, Program.cfg.DB_passwd, Program.cfg.DB_port);
|
|
while (isRunning)
|
|
{
|
|
|
|
while((++count % 5 != 0) && isRunning)
|
|
{
|
|
Thread.Sleep(100);
|
|
}
|
|
|
|
count = 0;
|
|
try
|
|
{
|
|
Dictionary<string, Status_for_tab> changedStatuses = new Dictionary<string, Status_for_tab>();
|
|
|
|
foreach (DictionaryEntry pair in MainForm.VehicleHashStat)
|
|
{
|
|
VehicleStatus vs = ((VehicleStatus)MainForm.VehicleHashStat[pair.Key]);
|
|
|
|
// change the status only if a last position is available or last Ars time is available
|
|
if(vs.lastPositionTime.Year > 2010 || vs.lastArsTime.Year > 2010)
|
|
{
|
|
//Utils.WriteLine("CHECKING UNIT STATUS : " + pair.Key + " | " + vs.curentStatus, ConsoleColor.Magenta);
|
|
switch (vs.curentStatus)
|
|
{
|
|
// NOTHING TO DO WHEN IN EMERGENCY
|
|
case Status_for_tab.EMERG:
|
|
break;
|
|
case Status_for_tab.DISABLE: break;
|
|
case Status_for_tab.ENABLE: break;
|
|
case Status_for_tab.OFF: break;
|
|
case Status_for_tab.MADEOFF: break;
|
|
case Status_for_tab.NOGPSFIX:
|
|
case Status_for_tab.GPS_OFF:
|
|
{
|
|
// check if the unit needs to be made off
|
|
if (CheckPositionMadeOff(vs))
|
|
{
|
|
// update status and push changes
|
|
vs.curentStatus = Status_for_tab.MADEOFF;
|
|
MulticastListener.PushStatus(pair.Key + "", vs.curentStatus);
|
|
|
|
}
|
|
break;
|
|
}
|
|
case Status_for_tab.MADEON:
|
|
case Status_for_tab.ON:
|
|
{
|
|
// check if the unit needs to be made off
|
|
if (CheckArsMadeOff(vs) && CheckPositionMadeOff(vs))
|
|
{
|
|
// update status and push changes
|
|
vs.curentStatus = Status_for_tab.MADEOFF;
|
|
MulticastListener.PushStatus(pair.Key + "", vs.curentStatus);
|
|
}
|
|
break;
|
|
}
|
|
case Status_for_tab.GPS_ON:
|
|
{
|
|
// check if the unit needs to be made off
|
|
if (CheckGpsPoor(vs))
|
|
{
|
|
// update status and push changes
|
|
vs.curentStatus = Status_for_tab.GPS_POOR;
|
|
MulticastListener.PushStatus(pair.Key + "", vs.curentStatus);
|
|
}
|
|
break;
|
|
}
|
|
case Status_for_tab.GPS_POOR:
|
|
{
|
|
// check if the unit needs to be made off
|
|
if (CheckGpsOff(vs))
|
|
{
|
|
// update status and push changes
|
|
vs.curentStatus = Status_for_tab.GPS_OFF;
|
|
MulticastListener.PushStatus(pair.Key + "", vs.curentStatus);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (vs.curentStatus != vs.previousStatus)
|
|
{
|
|
changedStatuses.Add(pair.Key + "", vs.curentStatus);
|
|
// force the previous status to become the same as the current status
|
|
vs.curentStatus = vs.curentStatus;
|
|
}
|
|
}
|
|
// update the statuses that changed
|
|
if (changedStatuses.Count > 0)
|
|
{
|
|
dbsubsoperManage.updateOnlyStatus(changedStatuses);
|
|
Utils.WriteLine(changedStatuses.Count + " units changed their states.", ConsoleColor.Green);
|
|
changedStatuses.Clear();
|
|
}
|
|
|
|
}
|
|
catch (ThreadAbortException tae)
|
|
{
|
|
Utils.WriteLine(tae.ToString(), ConsoleColor.Red);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.WriteLine("HandleUnitStatus Exception: " + ex.ToString(), ConsoleColor.Red);
|
|
}
|
|
} // end while (true)
|
|
}
|
|
|
|
|
|
private bool CheckArsMadeOff(VehicleStatus vehicleStatus)
|
|
{
|
|
return (DateTime.Now - vehicleStatus.lastArsTime).TotalSeconds > vehicleStatus.made_off ? true : false;
|
|
}
|
|
|
|
|
|
private bool CheckPositionMadeOff(VehicleStatus vehicleStatus)
|
|
{
|
|
return (DateTime.Now - vehicleStatus.lastPositionTime).TotalSeconds > vehicleStatus.made_off ? true : false;
|
|
}
|
|
|
|
|
|
private bool CheckGpsPoor(VehicleStatus vehicleStatus)
|
|
{
|
|
//Utils.WriteLine((DateTime.Now - vehicleStatus.lastPositionTime).TotalSeconds + "");
|
|
return (DateTime.Now - vehicleStatus.lastPositionTime).TotalSeconds > vehicleStatus.gps_poor ? true : false;
|
|
}
|
|
|
|
private bool CheckGpsOff(VehicleStatus vehicleStatus)
|
|
{
|
|
return (DateTime.Now - vehicleStatus.lastPositionTime).TotalSeconds > vehicleStatus.gps_off ? true : false;
|
|
}
|
|
/// <summary>
|
|
/// If the WebsocketServer is online populate a Dataset, convert it to JSON and send it on the websocket
|
|
/// </summary>
|
|
/// <param name="source"></param>
|
|
/// <param name="e"></param>
|
|
private static void SendLocationToWebSocketHandler(object source, ElapsedEventArgs e)
|
|
{
|
|
Utils.WriteLine("Preparing " + MainForm.websocketLocationQueue.Count + " positions to be sent to websocket!!!",
|
|
ConsoleColor.DarkYellow);
|
|
if(WebsocketThread.Instance.getClient() == null)
|
|
{
|
|
Utils.WriteLine("WebSocket client url not set or websocket not active");
|
|
MainForm.websocketLocationQueue.Clear();
|
|
return;
|
|
}
|
|
|
|
if (MainForm.websocketLocationQueue.Count > 0 && WebsocketThread.Instance.getClient().IsRunning)
|
|
{
|
|
List<UnitDataToSend> allPositions = MainForm.websocketLocationQueue.ToList();
|
|
|
|
// send over websocket and clear list
|
|
WebsocketThread.SendJson(WebsocketThread.Instance.getClient(), WebSocketFormatter.ToJson(allPositions));
|
|
}
|
|
|
|
MainForm.websocketLocationQueue.Clear();
|
|
}
|
|
|
|
private static void CheckGatewayStatus(object source, ElapsedEventArgs e)
|
|
{
|
|
if (Program.cfg.gatewayType == "SDR" && !IsProcessRunning("SDRgateway"))
|
|
{
|
|
try
|
|
{
|
|
string Path = $@"{SafeMobileLib.Utils.GetRegValue("Path", "SafeMobile")}\Tetra_SDR\SDRgateway.exe";
|
|
System.Diagnostics.Process.Start(Path);
|
|
SafeMobileLib.Utils.WriteLine("Gateway started", ConsoleColor.Yellow);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
Utils.WriteLine("Could not start Gateway because: " + ex.ToString() + Environment.NewLine + "Path to Gateway = " +
|
|
$@"{SafeMobileLib.Utils.GetRegValue("Path", "SafeMobile")}\Tetra_SDR\SDRgateway.exe", ConsoleColor.Red);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool IsProcessRunning(string ProcessName)
|
|
{
|
|
try
|
|
{
|
|
Process[] pname = Process.GetProcessesByName(ProcessName);
|
|
if (pname.Length == 0)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#region UPDATE
|
|
|
|
/// <summary>
|
|
/// Check for new version release on SafeMobile Portal
|
|
/// The check is done by comparing Current Assembly Version with the one
|
|
/// written in a xml file on the portal.
|
|
/// </summary>
|
|
private void CheckForUpdate()
|
|
{
|
|
App appType = App.APP_SERVER;
|
|
AutoUpdate au = new AutoUpdate(appType) { IsDevelop = Program.cfg.isDevelop };
|
|
au.OnNewVersionAvailable += delegate(string version)
|
|
{
|
|
notifyIcon1.Text = "New version available";
|
|
notifyIcon1.ShowBalloonTip(2500, $"{App.GetAppName(appType)} version {version} available",
|
|
$"Press to download and install the latest version of {App.GetAppName(appType)}.", ToolTipIcon.Info);
|
|
notifyIcon1.BalloonTipClicked += delegate (object sender, EventArgs e)
|
|
{
|
|
if (notifyIcon1.Text.Equals("New version available"))
|
|
{
|
|
UpdateForm uf = new UpdateForm(appType, true) { IsDevelop = Program.cfg.isDevelop };
|
|
uf.Show();
|
|
}
|
|
};
|
|
};
|
|
// call method to check for new updated
|
|
au.CheckUpdate();
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|