resharper tidying on a lot of files.

start padding out history pages.
update plugin extension points to use PluginDetails object to identify themselves.
implemented last scanned id methods to get last id from real ir daemon code to show on Race Director Page
This commit is contained in:
chris.watts90@outlook.com 2017-06-25 22:27:21 +01:00
parent 087242dd58
commit 38cfb67f62
70 changed files with 517 additions and 287 deletions

View File

@ -1,5 +1,4 @@
using System;
using System.Security.Cryptography;
using System.Security.Cryptography;
using System.Text;
namespace Helpers.Encryption

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@ -1,9 +1,4 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Interfaces
namespace Interfaces
{
public class ConfigurationSetting
{

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Interfaces
namespace Interfaces
{
public interface IConfigFilePathProvider
{

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Interfaces
{

View File

@ -1,6 +1,6 @@
namespace Interfaces
{
public interface INotifierProvider
public interface INotifierProvider : IPluginInformation
{
string GetDisplayName();
void NotifyRaceStarted(NotificationEventArgs args);

View File

@ -0,0 +1,7 @@
namespace Interfaces
{
public interface IPluginInformation
{
PluginDetails GetPluginDetails();
}
}

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Interfaces
namespace Interfaces
{
public interface IPluginPathProvider
{

View File

@ -1,6 +1,6 @@
namespace Interfaces
{
public interface ISystemControl
public interface ISystemControlProvider : IPluginInformation
{
void Shutdown();
}

View File

@ -2,6 +2,6 @@
{
public interface ISystemControlProviderFactory
{
ISystemControl GetProvider();
ISystemControlProvider GetProvider();
}
}

View File

@ -2,7 +2,7 @@
namespace Interfaces
{
public interface ITransponderUtilityProvider
public interface ITransponderUtilityProvider : IPluginInformation
{
Task<int> GetLastScannedIdAsync();
}

View File

@ -1,9 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Interfaces
namespace Interfaces
{
public interface IUserStorage
{

View File

@ -43,6 +43,7 @@
<Compile Include="IConfigFilePathProvider.cs" />
<Compile Include="IContainerHelper.cs" />
<Compile Include="ILoggerService.cs" />
<Compile Include="IPluginInformation.cs" />
<Compile Include="IPluginLocator.cs" />
<Compile Include="IPluginPathProvider.cs" />
<Compile Include="ConfigurationSetting.cs" />
@ -58,7 +59,7 @@
<Compile Include="ITransponderUtilityProviderFactory.cs" />
<Compile Include="NotificationEventArgs.cs" />
<Compile Include="Pilot.cs" />
<Compile Include="ProviderDetails.cs" />
<Compile Include="PluginDetails.cs" />
<Compile Include="RaceSession.cs" />
<Compile Include="IUserStorage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -0,0 +1,17 @@
namespace Interfaces
{
public class PluginDetails
{
public PluginDetails(string pluginName, string pluginAuthor, string pluginDescription, string pluginVersion)
{
PluginName = pluginName;
PluginAuthor = pluginAuthor;
PluginDescription = pluginDescription;
PluginVersion = pluginVersion;
}
public string PluginName { get; }
public string PluginAuthor { get; }
public string PluginDescription { get; }
public string PluginVersion { get; }
}
}

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Interfaces
{
public class ProviderDetails
{
public string ProviderName { get; set; }
public string ProviderAuthor { get; set; }
public string ProviderDescription { get; set; }
}
}

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Interfaces
{

View File

@ -2,11 +2,18 @@
namespace IrDaemonNotifier
{
public class IdDaemonTransponderUtilityFactory : ITransponderUtilityProviderFactory
public class IrDaemonTransponderUtilityFactory : ITransponderUtilityProviderFactory
{
private readonly ILoggerService _logger;
public IrDaemonTransponderUtilityFactory(ILoggerService logger)
{
_logger = logger;
}
public ITransponderUtilityProvider GetProvider()
{
return new IrDaemonTransponderUtilities();
return new IrDaemonTransponderUtilities(_logger);
}
}
}

View File

@ -0,0 +1,137 @@
using System.Net.Sockets;
using System.Text;
using Interfaces;
namespace IrDaemonNotifier
{
class IrDaemonCommunicator
{
private const string IRDAEMON_SERVER_IP = "192.168.1.65";
private const int IRDAEMON_PORT_NO = 3006;
private const int IRDAEMON_PROPERTY_PORT_NO = 3007;
private ILoggerService _logger;
public IrDaemonCommunicator(ILoggerService logger)
{
_logger = logger;
}
/// <summary>
/// Send a command to the IrDaemon endpoint
/// </summary>
/// <param name="command">string command name</param>
//TODO: convert to use an enum value perhaps? "supported command" style?
public void SendCommand(string command)
{
var formattedCommand = FormatCommand(command);
//---create a TCPClient object at the IP and port no.---
var client = new TcpClient(IRDAEMON_SERVER_IP, IRDAEMON_PORT_NO);
var nwStream = client.GetStream();
var bytesToSend = Encoding.ASCII.GetBytes(formattedCommand);
//---send the text---
_logger.Trace("Sending: {0}", formattedCommand);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//---read back the text---
var bytesToRead = new byte[client.ReceiveBufferSize];
var bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
_logger.Trace("Received: {0}", Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
client.Close();
}
/// <summary>
/// Get data from the IrDaemon for the requested property name
/// </summary>
/// <typeparam name="T">type to convert property value to</typeparam>
/// <param name="command">The name of the property to request data for</param>
/// <returns>the object returned from the ir daemon, converted to the Type T</returns>
public T RequestData<T>(string command)
{
try
{
var formattedCommand = FormatCommand(command);
//---create a TCPClient object at the IP and port no.---
var client = new TcpClient(IRDAEMON_SERVER_IP, IRDAEMON_PROPERTY_PORT_NO);
var nwStream = client.GetStream();
var bytesToSend = Encoding.ASCII.GetBytes(formattedCommand);
//---send the text---
_logger.Trace("Sending: {0}", formattedCommand);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//---read back the text---
var bytesToRead = new byte[client.ReceiveBufferSize];
var bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
var stringResponse = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead);
client.Close();
stringResponse = StripFormatting(stringResponse);
_logger.Trace("Received: {0}", stringResponse);
var strId = GetTokenIdString(stringResponse);
try
{
return Convert<T>(strId);
}
catch
{
return default(T);
}
}
catch (System.Exception ex)
{
_logger.Error(ex);
}
return default(T);
}
/// <summary>
/// Format the command string for the ir daemon "protocol"
/// </summary>
/// <param name="command">command to format</param>
/// <returns>formatted command</returns>
private string FormatCommand(string command)
{
return string.Format("#{0}#\n", command);
}
/// <summary>
/// remove the formatting from the string
/// </summary>
/// <param name="data">string to remove formatting from</param>
/// <returns>string with protocol formatting removed</returns>
private string StripFormatting(string data)
{
return data.Replace("#", "").Replace("\n", "");
}
private string GetTokenIdString(string data)
{
var bits = data.Split(' ');
if(bits.Length == 3)
return bits[1];
return string.Empty;
}
private T Convert<T>(string data)
{
return (T)System.Convert.ChangeType(data, typeof(T));
}
}
internal class Commands
{
public class Properties
{
public const string GetLastToken = "LAST_SCANNED_TOKEN";
}
public const string Shutdown = "SHUTDOWN";
public const string Reset = "RESET";
}
}

View File

@ -3,11 +3,16 @@ using Interfaces;
namespace IrDaemonNotifier
{
public class IrDaemonController:ISystemControl
public class IrDaemonController:ISystemControlProvider
{
public void Shutdown()
{
Debug.WriteLine("test");
}
public PluginDetails GetPluginDetails()
{
return Resources.Details;
}
}
}

View File

@ -4,7 +4,7 @@ namespace IrDaemonNotifier
{
public class IrDaemonControllerProviderFactory : ISystemControlProviderFactory
{
public ISystemControl GetProvider()
public ISystemControlProvider GetProvider()
{
return new IrDaemonController();
}

View File

@ -1,18 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Interfaces;
namespace IrDaemonNotifier
{
public class IrDaemonNotifier : INotifierProvider
{
private const int REMOTE_PORT_NO = 3006;
private const string REMOTE_SERVER_IP = "127.0.0.1";
private readonly ILoggerService _logger;
public IrDaemonNotifier(ILoggerService logger)
@ -25,32 +17,17 @@ namespace IrDaemonNotifier
return "Ir Daemon Notifier";
}
public string GetNotifierType()
public PluginDetails GetPluginDetails()
{
return nameof(IrDaemonNotifier);
return Resources.Details;
}
public void NotifyRaceStarted(NotificationEventArgs args)
{
try
{
//---data to send to the server---
var message = string.Format("#{0}#\n", "RESET");
//---create a TCPClient object at the IP and port no.---
var client = new TcpClient(REMOTE_SERVER_IP, REMOTE_PORT_NO);
var nwStream = client.GetStream();
var bytesToSend = Encoding.ASCII.GetBytes(message);
//---send the text---
_logger.Trace("Sending: {0}", message);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//---read back the text---
var bytesToRead = new byte[client.ReceiveBufferSize];
var bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
_logger.Trace("Received: {0}", Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
client.Close();
var communicator = new IrDaemonCommunicator(_logger);
communicator.SendCommand(Commands.Reset);
}
catch (Exception ex)
{
@ -73,5 +50,6 @@ namespace IrDaemonNotifier
public void NotifyRaceFinished(NotificationEventArgs args)
{
}
}
}

View File

@ -41,12 +41,14 @@
</ItemGroup>
<ItemGroup>
<Compile Include="IdDaemonTransponderUtilityFactory.cs" />
<Compile Include="IrDaemonCommunicator.cs" />
<Compile Include="IrDaemonController.cs" />
<Compile Include="IrDaemonControllerProviderFactory.cs" />
<Compile Include="IrDaemonNotifier.cs" />
<Compile Include="IrDaemonNotifierProviderFactory.cs" />
<Compile Include="IrDaemonTransponderUtilities.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Resources.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Interfaces\Interfaces.csproj">

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Interfaces;
using Interfaces;
namespace IrDaemonNotifier
{

View File

@ -5,9 +5,28 @@ namespace IrDaemonNotifier
{
public class IrDaemonTransponderUtilities : ITransponderUtilityProvider
{
private readonly ILoggerService _logger;
public IrDaemonTransponderUtilities(ILoggerService logger)
{
_logger = logger;
}
public Task<int> GetLastScannedIdAsync()
{
return Task.FromResult(-1);
return Task.Run(()=>GetLastId());
}
public PluginDetails GetPluginDetails()
{
return Resources.Details;
}
private int GetLastId()
{
//TODO: implement caching here, network/request latency is mega, always exceeds 1second, this is too much
var communicator = new IrDaemonCommunicator(_logger);
return communicator.RequestData<int>(Commands.Properties.GetLastToken);
}
}
}

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@ -0,0 +1,9 @@
using Interfaces;
namespace IrDaemonNotifier
{
public static class Resources
{
public static readonly PluginDetails Details = new PluginDetails("IrDaemonNotifier", "Chris Watts", "IR Daemon Interface", "1.0.0.0");
}
}

View File

@ -9,7 +9,7 @@ namespace NLogLogger
{
public class NLogLoggingService : ILoggerService
{
private readonly NLog.Logger _logger;
private readonly Logger _logger;
public NLogLoggingService(IConfigFilePathProvider configFileFolder)
{
var cfgFilePath = Path.Combine(configFileFolder.GetPath, "NLogConfig.xml");

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@ -9,17 +9,17 @@ namespace RaceLapTimer.ApiControllers
public LapTrackApiModule(IDbProvider provider) : base("/api/laptrack")
{
_dbProvider = provider;
Get["/create"] = args => LogLapTime(args);
Get["/create"] = args => LogLapTime();
}
private dynamic LogLapTime(dynamic args)
private dynamic LogLapTime()
{
var transponderToken = Convert.ToInt32(Request.Query["transponder_token"]);
var lapTimeInMs = Convert.ToInt32(Request.Query["lap_time_in_ms"]);
var log = new SatelliteLog
{
TransponderToken = transponderToken,
LapTimeMS = lapTimeInMs
LapTimeMs = lapTimeInMs
};
_dbProvider.StoreTransponderLog(log);
return HttpStatusCode.OK;

View File

@ -1,5 +1,4 @@
using System.Runtime.InteropServices;
using Nancy;
using Nancy;
namespace RaceLapTimer.ApiControllers
{
@ -10,10 +9,10 @@ namespace RaceLapTimer.ApiControllers
{
_provider = provider;
Get[""] = args => GetRootMonitorData(args);
Get[""] = args => GetRootMonitorData();
}
private dynamic GetRootMonitorData(dynamic args)
private dynamic GetRootMonitorData()
{
return Response.AsJson(new { data = _provider.GetRaceSessions(true)});
}

View File

@ -1,16 +1,14 @@
using System;
using System.IO;
using System.Linq;
using System.Web.Http;
using Interfaces;
using Nancy;
using Nancy.Extensions;
using Nancy.ModelBinding;
using Nancy.Responses;
namespace RaceLapTimer.ApiControllers
{
public class PilotApiModule:NancyModule
public class PilotApiModule : NancyModule
{
private readonly IDbProvider _provider;
private readonly IRootPathProvider _rootPathProvider;
@ -21,8 +19,8 @@ namespace RaceLapTimer.ApiControllers
_rootPathProvider = pathProvider;
Get["/{id}"] = args => GetPilot(args);
Post["/edit"] = args => EditCreatePilot(args);
Post["/create"] = args => EditCreatePilot(args);
Post["/edit"] = args => EditCreatePilot();
Post["/create"] = args => EditCreatePilot();
Get["/delete/{id}"] = args => DeletePilot(args);
Post["/upload/{id}"] = args => UploadPicture(args);
}
@ -43,11 +41,11 @@ namespace RaceLapTimer.ApiControllers
var file = Request.Files.First();
var newFileName = Guid.NewGuid();
var generatedFileName = string.Format("{0}{1}",newFileName,Path.GetExtension(file.Name)); //0000-0000.....ext
var generatedFileName = string.Format("{0}{1}", newFileName, Path.GetExtension(file.Name)); //0000-0000.....ext
var filename = Path.Combine(uploadDirectory, generatedFileName);
using (FileStream fileStream = new FileStream(filename, FileMode.Create))
using (var fileStream = new FileStream(filename, FileMode.Create))
{
file.Value.CopyTo(fileStream);
fileStream.Flush();
@ -66,7 +64,7 @@ namespace RaceLapTimer.ApiControllers
private dynamic DeletePilot(dynamic args)
{
var res = _provider.DeletePilot(args.Id);
return Response.AsRedirect("/pilots");
return Context.GetRedirect("/pilots");
}
private dynamic GetPilot(dynamic args)
@ -75,7 +73,7 @@ namespace RaceLapTimer.ApiControllers
return Response.AsJson(_provider.GetPilot(pilotId));
}
private dynamic EditCreatePilot(dynamic args)
private dynamic EditCreatePilot()
{
var pilotObject = this.Bind<Pilot>();
var resp = _provider.CreatePilot(pilotObject);

View File

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using Interfaces;
using Nancy;
using Nancy.Extensions;
using Nancy.ModelBinding;
using Nancy.Responses;
namespace RaceLapTimer.ApiControllers
{
@ -19,8 +17,16 @@ namespace RaceLapTimer.ApiControllers
_notifier = notifierManager;
Get[""] = args => GetRaceSessions();
Post["/create"] = args => CreateRaceSession(args);
Post["/create"] = args => CreateRaceSession();
Get["/historic"] = args => GetHistoricRaceSessions();
Delete["/historic/{id}"] = args => DeleteHistoricRaceSession(args);
}
private dynamic DeleteHistoricRaceSession(dynamic args)
{
int raceSessionId = args.Id;
var res = _provider.DeleteRaceSession(raceSessionId);
return Context.GetRedirect("/history");
}
private dynamic GetHistoricRaceSessions()
@ -35,7 +41,7 @@ namespace RaceLapTimer.ApiControllers
return Response.AsJson(new { data = sessions });
}
private dynamic CreateRaceSession(dynamic args)
private dynamic CreateRaceSession()
{
var session = this.Bind<RaceSession>();
var res = _provider.CreateRaceSession(session);

View File

@ -10,17 +10,17 @@ namespace RaceLapTimer.ApiControllers
{
_provider = provider;
Get[""] = args => LogNewLapSatelliteTime(args);
Get[""] = args => LogNewLapSatelliteTime();
}
private dynamic LogNewLapSatelliteTime(dynamic args)
private dynamic LogNewLapSatelliteTime()
{
var transponderToken = Convert.ToInt32(Request.Query["transponder_token"]);
var lapTimeMs = Convert.ToInt32(Request.Query["lap_time_in_ms"]);
var logObj = new SatelliteLog
{
TransponderToken = transponderToken,
LapTimeMS = lapTimeMs
LapTimeMs = lapTimeMs
};
_provider.StoreTransponderLog(logObj);
return HttpStatusCode.OK;
@ -30,6 +30,6 @@ namespace RaceLapTimer.ApiControllers
public class SatelliteLog
{
public int TransponderToken { get; set; }
public int LapTimeMS { get; set; }
public int LapTimeMs { get; set; }
}
}

View File

@ -1,5 +1,4 @@
using System.Web.Http;
using Nancy;
using Nancy;
namespace RaceLapTimer.ApiControllers
{

View File

@ -1,18 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using Interfaces;
using Nancy;
namespace RaceLapTimer.ApiControllers
{
public class SystemApiModule : NancyModule
{
public SystemApiModule() : base("/api/system")
private readonly ITransponderUtilityManager _transponderManager;
public SystemApiModule(ITransponderUtilityManager transponderManager)
: base("/api/system")
{
_transponderManager = transponderManager;
Get["info"] = args => GetSystemInfo();
Get["lasttoken"] = args => GetLastToken();
}
private dynamic GetSystemInfo()
@ -23,6 +25,11 @@ namespace RaceLapTimer.ApiControllers
Version = Assembly.GetEntryAssembly().GetName().Version.ToString()
});
}
private dynamic GetLastToken()
{
return Response.AsJson(new { Id=_transponderManager.GetLastScannedId()});
}
}
public class SystemInfo

View File

@ -1,18 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace RaceLapTimer.Helpers
namespace RaceLapTimer.Assists
{
public static class AsyncHelpers
{
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// <![CDATA[Execute's an async Task<T> method which has a void return value synchronously]]>
/// </summary>
/// <param name="task">Task<T> method to execute</param>
/// <param name="task"><![CDATA[Task<T> method to execute]]></param>
public static void RunSync(Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
@ -40,10 +38,10 @@ namespace RaceLapTimer.Helpers
}
/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// <![CDATA[Execute's an async Task<T> method which has a T return type synchronously]]>
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <param name="task"><![CDATA[Task<T> method to execute]]></param>
/// <returns></returns>
public static T RunSync<T>(Func<Task<T>> task)
{
@ -74,10 +72,10 @@ namespace RaceLapTimer.Helpers
private class ExclusiveSynchronizationContext : SynchronizationContext
{
private bool done;
private bool _done;
public Exception InnerException { get; set; }
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> items =
readonly AutoResetEvent _workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> _items =
new Queue<Tuple<SendOrPostCallback, object>>();
public override void Send(SendOrPostCallback d, object state)
@ -87,28 +85,28 @@ namespace RaceLapTimer.Helpers
public override void Post(SendOrPostCallback d, object state)
{
lock (items)
lock (_items)
{
items.Enqueue(Tuple.Create(d, state));
_items.Enqueue(Tuple.Create(d, state));
}
workItemsWaiting.Set();
_workItemsWaiting.Set();
}
public void EndMessageLoop()
{
Post(_ => done = true, null);
Post(_ => _done = true, null);
}
public void BeginMessageLoop()
{
while (!done)
while (!_done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (items)
lock (_items)
{
if (items.Count > 0)
if (_items.Count > 0)
{
task = items.Dequeue();
task = _items.Dequeue();
}
}
if (task != null)
@ -121,7 +119,7 @@ namespace RaceLapTimer.Helpers
}
else
{
workItemsWaiting.WaitOne();
_workItemsWaiting.WaitOne();
}
}
}

View File

@ -29,8 +29,8 @@ namespace RaceLapTimer
// Configure things for a wider purpose, non-requestcontroller based.
container.Bind<IContainerHelper>().To<ContainerHelper>();
container.Bind<IPluginPathProvider>().To<PluginPathProvider>();
container.Bind<IPluginLocator>().To<PluginLocator>();
container.Bind<IConfigFilePathProvider>().To<ConfigFilePathProvider>();
container.Bind<IPluginLocator>().To<PluginLocator>();
container.Bind<IDbProvider>().To<TestProvider>().InSingletonScope();
//load dynamic plugins..:
var cfgFilePath = Path.Combine(container.Get<IConfigFilePathProvider>().GetPath, "NinjectConfig.xml");
@ -41,8 +41,8 @@ namespace RaceLapTimer
container.Bind<ISystemControlManager>().To<SystemControlManager>().InSingletonScope();
container.Bind<ITransponderUtilityManager>().To<TransponderUtilityManager>().InSingletonScope();
var tM = container.Get<ITransponderUtilityManager>();
tM.GetLastScannedId();
var tu = container.Get<ITransponderUtilityManager>();
var id = tu.GetLastScannedId();
}
protected override void ConfigureRequestContainer(IKernel container, NancyContext context)

View File

@ -1,10 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Interfaces;
namespace RaceLapTimer

View File

@ -77,19 +77,5 @@ namespace RaceLapTimer.Extensions.Notifications
Task.Factory.StartNew(() => provider.NotifyRaceFinished(args));
}
}
private bool IsAssembly(string extension)
{
var validAssemblyExts = new List<string>
{
"dll", "exe"
};
var ext = extension.Remove(0, 1);
if (validAssemblyExts.Contains(ext))
{
return true;
}
return false;
}
}
}

View File

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Interfaces;
@ -50,7 +48,6 @@ namespace RaceLapTimer.Extensions
discoveryList.Add(new DiscoveredPlugin
{
FilePath = file,
PluginType = pluginTypes.First(),
TypeToBindTo = typeof(T),
UniqueName = Path.GetFileNameWithoutExtension(file)
});
@ -110,7 +107,6 @@ namespace RaceLapTimer.Extensions
private class DiscoveredPlugin
{
public string FilePath { get; set; }
public Type PluginType { get; set; }
public Type TypeToBindTo { get; set; }
public string UniqueName { get; set; }
}

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Interfaces;
@ -9,7 +8,7 @@ namespace RaceLapTimer.Extensions.SystemControl
{
class SystemControlManager : ISystemControlManager
{
private List<ISystemControl> _providers;
private List<ISystemControlProvider> _providers;
private readonly ILoggerService _logger;
public SystemControlManager(IPluginLocator locator, ILoggerService logger)
@ -23,7 +22,7 @@ namespace RaceLapTimer.Extensions.SystemControl
try
{
var providerFactories = locator.Locate<ISystemControlProviderFactory>();
_providers = new List<ISystemControl>();
_providers = new List<ISystemControlProvider>();
foreach (var factory in providerFactories)
{
_providers.Add(factory.GetProvider());

View File

@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Interfaces;
using RaceLapTimer.Helpers;
using RaceLapTimer.Assists;
namespace RaceLapTimer.Extensions.TransponderUtilities
{

View File

@ -12,6 +12,8 @@ namespace RaceLapTimer
bool StopRaceSession(RaceSession session);
bool DeleteRaceSession(int raceSessionId);
List<Pilot> GetPilotsList();
Pilot GetPilot(int pilotId);

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
namespace RaceLapTimer.Modules
@ -11,12 +7,12 @@ namespace RaceLapTimer.Modules
{
public HistoryModule():base("/history")
{
Get[""] = args => GetHistoryHomePage(args);
Get[""] = args => GetHistoryHomePage();
}
private dynamic GetHistoryHomePage(dynamic args)
private dynamic GetHistoryHomePage()
{
throw new NotImplementedException();
return View["HistoryIndex.cshtml"];
}
}
}

View File

@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy.Authentication.Forms;
using Nancy.Extensions;
@ -14,35 +10,35 @@ namespace RaceLapTimer.Modules
{
public LoginModule()
{
Get["/login"] = args => GetLoginPage(args);
Get["/login"] = args => GetLoginPage();
Post["/login"] = args => PostLoginAttempt(args);
Post["/login"] = args => PostLoginAttempt();
Get["/logout"] = args => {
return this.LogoutAndRedirect("~/");
};
}
private dynamic GetLoginPage(dynamic args)
private dynamic GetLoginPage()
{
dynamic model = new ExpandoObject();
model.Errored = this.Request.Query.error.HasValue;
model.Errored = Request.Query.error.HasValue;
return View["login", model];
}
private dynamic PostLoginAttempt(dynamic args)
private dynamic PostLoginAttempt()
{
var userGuid = UserDatabase.ValidateUser((string)this.Request.Form.Username,
(string)this.Request.Form.Password);
var userGuid = UserDatabase.ValidateUser((string)Request.Form.Username,
(string)Request.Form.Password);
if (userGuid == null)
{
return this.Context.GetRedirect("~/login?error=true&username=" + (string)this.Request.Form.Username);
return Context.GetRedirect("~/login?error=true&username=" + (string)Request.Form.Username);
}
DateTime? expiry = null;
if (this.Request.Form.RememberMe.HasValue)
if (Request.Form.RememberMe.HasValue)
{
expiry = DateTime.Now.AddDays(7);
}

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy;
namespace RaceLapTimer.Modules
{
@ -11,11 +6,11 @@ namespace RaceLapTimer.Modules
{
public MonitorModule()
{
Get[""] = args => GetMonitorHomePage(args);
Get["/monitor"] = args => GetMonitorHomePage(args);
Get[""] = args => GetMonitorHomePage();
Get["/monitor"] = args => GetMonitorHomePage();
}
private dynamic GetMonitorHomePage(dynamic args)
private dynamic GetMonitorHomePage()
{
return View["Monitor.cshtml"];
}

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy;
using Nancy.Security;
namespace RaceLapTimer.Modules

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy;
namespace RaceLapTimer.Modules
{
@ -11,10 +6,10 @@ namespace RaceLapTimer.Modules
{
public PilotsModule() : base("/pilots")
{
Get[""] = args => GetPilotsListHomePage(args);
Get[""] = args => GetPilotsListHomePage();
}
private dynamic GetPilotsListHomePage(dynamic args)
private dynamic GetPilotsListHomePage()
{
return View["Pilots.cshtml"];
}

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy;
using Nancy.Security;
namespace RaceLapTimer.Modules
@ -14,11 +9,11 @@ namespace RaceLapTimer.Modules
{
this.RequiresAuthentication();
Get[""] = args => GetRaceDirectoryHomePage(args);
Get[""] = args => GetRaceDirectoryHomePage();
//API METHOD - Get["lapTimes"]
}
private dynamic GetRaceDirectoryHomePage(dynamic args)
private dynamic GetRaceDirectoryHomePage()
{
return View["RaceDirector.cshtml"];
}

View File

@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy.Security;
namespace RaceLapTimer.Modules
{
public class SoundfileModule:NancyModule
public class SoundfileModule : NancyModule
{
public SoundfileModule() : base("/soundfile")
{

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy.Security;
@ -29,7 +25,7 @@ namespace RaceLapTimer.Modules
//this will return system configuration settings home page.
private dynamic GetSystemHomePage(dynamic args)
{
throw new NotImplementedException();
return View["SystemIndex.cshtml"];
}
//system/pilot/create //api method

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nancy;
using Nancy;
namespace RaceLapTimer.Modules
{

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.ServiceProcess;
namespace RaceLapTimer
{
@ -14,12 +9,12 @@ namespace RaceLapTimer
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
ServiceBase[] servicesToRun;
servicesToRun = new ServiceBase[]
{
new RaceLapTimer()
};
ServiceBase.Run(ServicesToRun);
ServiceBase.Run(servicesToRun);
}
}
}

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@ -117,6 +117,7 @@
<Compile Include="Extensions\PluginLocator.cs" />
<Compile Include="Extensions\SystemControl\SystemControlManager.cs" />
<Compile Include="Extensions\TransponderUtilities\TransponderUtilityManager.cs" />
<Compile Include="Assists\AsyncHelpers.cs" />
<Compile Include="IDbProvider.cs" />
<Compile Include="ApiControllers\LapTrackApiModule.cs" />
<Compile Include="ApiControllers\MonitorApiModule.cs" />
@ -166,6 +167,9 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="www\Views\History.cshtml" />
<None Include="www\Views\HistoryIndex.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="www\Views\index.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@ -187,6 +191,7 @@
<None Include="www\Views\secure.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="www\Views\SystemIndex.cshtml" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
@ -222,6 +227,12 @@
</Content>
<Content Include="www\js\bootstrap.js" />
<Content Include="www\js\bootstrap.min.js" />
<Content Include="www\js\LastScannedId.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="www\js\moment.min.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="www\js\monitor.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
@ -229,6 +240,9 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="www\js\npm.js" />
<Content Include="www\js\raceHistory.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="www\js\RaceSessionObject.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

View File

@ -83,7 +83,22 @@ namespace RaceLapTimer
Title = "TEST Session 3"
},
#endregion
#region Session 3
#region Session 4
new RaceSession
{
Active = false,
CreatedAt = DateTime.UtcNow,
HotSeatEnabled = false,
Id = 4,
IdleTimeSeconds = 400,
Mode = RaceMode.STANDARD,
MaxLaps = 10,
SatelliteCount = 1,
TimePenaltyPerSatellite = 100,
Title = "TEST Session 4"
},
#endregion
#region Session 5
new RaceSession
{
Active = false,
@ -129,6 +144,16 @@ namespace RaceLapTimer
return true;
}
public bool DeleteRaceSession(int sessionId)
{
if (_sessions.All(x => x.Id != sessionId))
{
return false;
}
var session = _sessions.Find(x => x.Id == sessionId);
return _sessions.Remove(session);
}
public List<Pilot> GetPilotsList()
{
return _pilots;

View File

@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Interfaces;
using Nancy;
using Nancy.Authentication.Forms;
@ -13,14 +10,14 @@ namespace RaceLapTimer
{
public class UserDatabase : IUserMapper
{
private static List<Tuple<string, string, Guid>> users = new List<Tuple<string, string, Guid>>();
private static List<Tuple<string, string, Guid>> _users = new List<Tuple<string, string, Guid>>();
private IUserStorage _storage;
public UserDatabase(IUserStorage storage)
{
_storage = storage;
users.Add(new Tuple<string, string, Guid>("admin", "password", new Guid("55E1E49E-B7E8-4EEA-8459-7A906AC4D4C0")));
users.Add(new Tuple<string, string, Guid>("user", "password", new Guid("56E1E49E-B7E8-4EEA-8459-7A906AC4D4C0")));
_users.Add(new Tuple<string, string, Guid>("admin", "password", new Guid("55E1E49E-B7E8-4EEA-8459-7A906AC4D4C0")));
_users.Add(new Tuple<string, string, Guid>("user", "password", new Guid("56E1E49E-B7E8-4EEA-8459-7A906AC4D4C0")));
}
/// <summary>
@ -31,7 +28,7 @@ namespace RaceLapTimer
/// <returns></returns>
public IUserIdentity GetUserFromIdentifier(Guid identifier, NancyContext context)
{
var userRecord = users.FirstOrDefault(u => u.Item3 == identifier);
var userRecord = _users.FirstOrDefault(u => u.Item3 == identifier);
return userRecord == null
? null
: new NancyUser(userRecord.Item1);
@ -51,7 +48,7 @@ namespace RaceLapTimer
pwHash = Helpers.Encryption.Hash.HashString(password);
}
var userRecord = users.FirstOrDefault(u => u.Item1 == username && u.Item2 == password);
var userRecord = _users.FirstOrDefault(u => u.Item1 == username && u.Item2 == password);
return userRecord?.Item3;
}

View File

@ -0,0 +1,61 @@
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>
@{
Layout = "razor-layout.cshtml";
ViewBag.Title = "History";
}
<h3>@ViewBag.Title</h3>
<table class="table table-striped dataTable">
<thead>
<tr>
<th></th>
<th class="col-md-2"></th>
<th>Session</th>
<th class="col-md-1">Mode</th>
<th class="col-md-1">Pilots</th>
<th></th>
</tr>
</thead>
<tbody data-bind="foreach: sessions, visible: sessions().length > 0">
<tr data-toggle="collapse" data-bind="attr: { 'data-target': '#collapse' + id() }">
<td class="text-center" data-bind="text: id"></td>
<td class="col-md-2" data-bind="text: createdDate">June 16, 2017 19:07</td>
<td data-bind="text: title">Race Name 1</td>
<td class="col-md-1" data-bind="text: mode">standard</td>
<td class="text-center col-md-1" >5</td>
<td class="col-md-3 text-center">
<button type="button" class="btn btn-warning" data-bind="click: $root.deleteSession">Delete</button>
<button type="button" class="btn btn-default">Export as PDF</button>
</td>
<td><span class="glyphicon glyphicon-plus"></span></td>
</tr>
<tr class="collapse" data-bind="attr:{ id: 'collapse' + id()}">
<td colspan="6">
<h4>Race Information</h4>
<div class="col-md-10 col-md-push-1">
<table class="table table-responsive">
<thead>
<tr>
<th>Total Laps</th>
<th>Fastest Lap</th>
<th>Fastest Pilot</th>
<th>Average Lap Time</th>
</tr>
</thead>
<tbody>
<tr>
<td data-bind="text: maxLaps">12</td>
<td>30.0s</td>
<td>a pilot</td>
<td>35.0s</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
<script src="js/moment.min.js" type="text/javascript"></script>
<script src="js/RaceSessionObject.js" type="text/javascript"></script>
<script src="js/raceHistory.js" type="text/javascript"></script>

View File

@ -7,7 +7,7 @@
<h3>@ViewBag.Title</h3>
<h4>Last Scanned Id</h4>
<label>None</label>
<label data-bind="text: lastId().id">Unknown</label>
<h4>Current Race</h4>
<label>None</label>
@ -50,5 +50,6 @@
<button type="submit" class="btn btn-default">Submit</button>
</form>
<script type="text/javascript" src="js/RaceSessionObject.js"></script>
<script type="text/javascript" src="js/LastScannedId.js"></script>
<script type="text/javascript" src="js/raceDirector.js"></script>
<script type="text/javascript" src="js/supportingPages.js"></script>

View File

@ -0,0 +1,6 @@
@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic>
@{
Layout = "razor-layout.cshtml";
ViewBag.Title = "Pilots";
ViewBag.CreateUserEndpoint = "/api/pilot/create";
}

View File

@ -0,0 +1,4 @@
function LastScannedId(data) {
var self = this;
self.id = ko.observable(data.id);
}

View File

@ -1,7 +1,10 @@
function RaceSession(data) {
var self = this;
self.id = ko.observable(data.id);
self.createdDate = ko.observable(data.createdDate);
self.createdAt = ko.observable(data.createdAt);
self.createdDate = ko.computed(function () {
return new moment(self.createdAt()).format("MMMM Do YYYY, HH:mm");
}, self);
self.updatedAt = ko.observable(data.updatedAt);
self.title = ko.observable(data.title);
self.active = ko.observable(data.active);

File diff suppressed because one or more lines are too long

View File

@ -2,13 +2,23 @@
"use strict";
var self = this;
self.raceSession = ko.observable(new RaceSession({id:-1, createdDate:"", updatedAt:"", title:"", active:false, mode:0, maxLaps:0, deletedAt:"", satelliteCount:0,timePenaltyPerSatellite:0, hotSeatEnabled:true, idleTimeSeconds:50}));
self.lastId = ko.observable(new LastScannedId({id:-1}));
//self.raceSessions = ko.observable();
//$.get("/api/monitor", {}, self.raceSession);
//self.tmrHandle = setTimeout(function () {
// self.getData();
//}, 2000);
self.tmrHandle = setTimeout(function () {
self.getLastId();
}, 2000);
self.getLastId = function() {
$.get("/api/system/lasttoken", {},
function (data) {
self.lastId(new LastScannedId(data));
})
.always(function () {
self.tmrHandle = setTimeout(self.getLastId, 2000);
});
};
//self.getData = function () {
// $.get("/api/monitor", {}, self.raceSession)
// .done(function () {

View File

@ -0,0 +1,31 @@
function ViewModel() {
var self = this;
self.deletePilotUrl = "/api/racesession/historic/";
self.sessions = ko.observableArray([]);
self.deleteSession = function (raceSession) {
$.ajax({
type: "DELETE",
url: self.deletePilotUrl + raceSession.id()
});
return false;
};
$.getJSON("/api/racesession/historic", function (allData) {
var mappedSessions = $.map(allData.data, function (item) { return new RaceSession(item) });
self.sessions(mappedSessions);
});
};
ko.applyBindings(new ViewModel());
function toggleIcon(e) {
$(e.target)
.toggleClass("glyphicon-plus glyphicon-minus");
}
$(".dataTable").on("hidden.bs.collapse",
function toggleIcon(e) {
$(e.target)
.toggleClass("glyphicon-plus glyphicon-minus");
});
$(".dataTable").on("shown.bs.collapse",
function toggleIcon(e) {
$(e.target)
.toggleClass("glyphicon-plus glyphicon-minus");
});

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@ -1,5 +1,4 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following

View File

@ -1,5 +1,4 @@
using System;
using System.Net;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Interfaces;
@ -14,14 +13,15 @@ namespace UdpNotifier
{
_logger = logger;
}
public string GetDisplayName()
{
return "UDP Notifier";
}
public string GetNotifierType()
public PluginDetails GetPluginDetails()
{
return "UdpNotifierProvider";
return new PluginDetails("UdpNotifier", "Chris Watts", "UDP Notification engine", "1.0.0.0");
}
public void NotifyRaceStarted(NotificationEventArgs args)
@ -52,12 +52,25 @@ namespace UdpNotifier
private void Send()
{
var endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.94"), 64000);
var endpoint = new IPEndPoint(IPAddress.Parse(GetLocalIp()), 0);
var client = new UdpClient(endpoint);
var ip = new IPEndPoint(IPAddress.Broadcast, 15000);
var bytes = Encoding.ASCII.GetBytes("Foo");
client.Send(bytes, bytes.Length, ip);
client.Close();
}
private string GetLocalIp()
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
return "0.0.0.0";
}
}
}

View File

@ -1,8 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Interfaces;
using Interfaces;
namespace UdpNotifier
{