using Autofac; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.ServiceProcess; using System.Threading.Tasks; using System.Timers; using Vec.Calculation.BL.Workflow; using Vec.Calculation.DAL; using Vec.Calculation.Model; using Vec.Common.Entities; using Vec.ComputerCount.DAL; using Vec.ComputerCount.DALReporting; using Vec.ComputerCount.Entities; using Vec.Framework.Core; using Vec.Framework.Core.BootStrappers; using Vec.Logger; using Vec.Logger.Helpers; using Vec.Logger.LogSinks; namespace Vec.WinServices.Calculation { public partial class CalculationEngine : ServiceBase { private int WaitTimeMili; private Timer timer1; private static IGlogger _logger; public CalculationEngine() { InitializeComponent(); WaitTimeMili = int.Parse(ConfigurationManager.AppSettings["WaitTime"]) * 1000; timer1 = new Timer(1000); timer1.Elapsed += Timer1_Elapsed; var loggerApiUrl = ConfigurationManager.AppSettings["LoggerApiUrl"]; if (!string.IsNullOrEmpty(loggerApiUrl)) { loggerApiUrl += "logs"; } } private void Timer1_Elapsed(object sender, ElapsedEventArgs e) { timer1.Enabled = false; timer1.Interval = WaitTimeMili; QueuedCalculation newCalculation = null; try { using (var db = new ResultsEntities()) { newCalculation = db.GetOneQueuedCalculation(); if (newCalculation != null) { if (newCalculation.CalculationMethod == (int)CalculationMethod.Countback) { StartNewCountbackTask(newCalculation); } else { StartNewCalculationTask(newCalculation.CalculationId, newCalculation.ElectionElectorateVacancyId, newCalculation.Vacancies, (CalculationMethod)newCalculation.CalculationMethod, (TieMethodType)newCalculation.TieMethod, (TieResolutionLogic)newCalculation.TieResolutionLogic, newCalculation.ExcludedCandidates, newCalculation.Status, newCalculation.ElectionCategory); } timer1.Interval = 1000; } } } catch (Exception ex) { try { LogException(ex).Wait(); } catch { } } finally { timer1.Start(); } } private void StartNewCalculationTask(Guid CalculationId, Guid ElectionElectorateVacancyId, int Vacancies, CalculationMethod CalculationMethod, TieMethodType TieMethodType, TieResolutionLogic TieResolutionLogic, string ExcludedCandidates, string Status, int ElectionCategory) { new Task(() => { using (var calculationContext = new ResultsEntities()) { var ccContext = (IComputerCountResolver)new ComputerCountResolver(); var reporting = (IReportingDAL)new ReportingDAL((IDataWarehouseDataContextWrapper)new DataWarehouseDataContextWrapper()); CalculateWorkflow wf; switch (CalculationMethod) { case CalculationMethod.Preferential: wf = new CalculatePref(CalculationId, ElectionElectorateVacancyId, TieMethodType, TieResolutionLogic, ExcludedCandidates, (ElectionCategory)ElectionCategory, ccContext, reporting, (ICalculationContext)calculationContext, IsSavingData: true); break; case CalculationMethod.Proportional: wf = new CalculatePR(CalculationId, ElectionElectorateVacancyId, Vacancies, TieMethodType, TieResolutionLogic, ExcludedCandidates, (ElectionCategory)ElectionCategory, ccContext, reporting, (ICalculationContext)calculationContext, IsSavingData: true); break; default: throw new NotImplementedException("Calculation Method Not Implemented."); } try { switch (Status.ToUpper()) { case "QUED": wf.Initialise(); wf.Calculate(); break; } } catch (Exception ex) { try { LogException(ex).Wait(); } catch { } calculationContext.UpdateCalculationAsFailed(CalculationId, ex.Message); } } }, TaskCreationOptions.LongRunning).Start(); } private void StartNewCountbackTask(QueuedCalculation queuedCalculation) { new Task(() => { using (var calculationContext = new ResultsEntities()) { var ccContext = (IComputerCountResolver)new ComputerCountResolver(); var reporting = (IReportingDAL)new ReportingDAL((IDataWarehouseDataContextWrapper)new DataWarehouseDataContextWrapper()); MCandidate vacatingCandidate = new MCandidate() { Position = queuedCalculation.VacatingCandidate.GetValueOrDefault() }; CalculateWorkflow countbackPR = new CountbackPR(queuedCalculation.CalculationId , queuedCalculation.CountbackId.GetValueOrDefault() , queuedCalculation.ElectionElectorateVacancyId , queuedCalculation.Vacancies , queuedCalculation.InitialCalculationId.GetValueOrDefault() , vacatingCandidate , (TieMethodType)queuedCalculation.TieMethod , (TieResolutionLogic)queuedCalculation.TieResolutionLogic , queuedCalculation.ExcludedCandidates , (ElectionCategory)queuedCalculation.ElectionCategory , ccContext , reporting , calculationContext , true); try { switch (queuedCalculation.Status.ToUpper()) { case "QUED": countbackPR.Initialise(); countbackPR.Calculate(); break; } } catch (Exception ex) { try { LogException(ex).Wait(); } catch { } calculationContext.UpdateCalculationAsFailed(queuedCalculation.CalculationId, ex.Message); } } }, TaskCreationOptions.LongRunning).Start(); } public void StartDebug() { this.OnStart(null); } protected override void OnStart(string[] args) { EventLogging.Write("Calculation Engine Started"); InitiateContainers(); timer1.Start(); } protected override void OnStop() { timer1.Stop(); EventLogging.Write("Calculation Engine Stopped."); } protected void InitiateContainers() { var builder = new ContainerBuilder(); var bootStrappers = GetBootStrappers(); foreach (var item in bootStrappers) { item.RegisterTypes(builder); } ServiceLocator.Container = builder.Build(); foreach (var item in bootStrappers) { item.Start(); } } private IEnumerable GetBootStrappers() { var bootStrapperList = new List { new ComputerCount.DAL.BootStrapper(), new ComputerCount.DALReporting.BootStrapper() }; return bootStrapperList; } private static async Task LogException(Exception ex) { if (_logger != null) { await _logger.LogErrorAsync(ex.ToBetterString()); } } } }