diff --git a/Action/Rs232Command.cs b/Action/Rs232Command.cs index 12db207c..85d24add 100644 --- a/Action/Rs232Command.cs +++ b/Action/Rs232Command.cs @@ -12,7 +12,8 @@ public class Rs232Command private Command _command; private SerialPort _port; - private string _toSend; + private string _toSend = null; + private bool _useHex = false; public Rs232Command(Command command) { @@ -39,7 +40,15 @@ public string Run() try { // Write our data stream - _port.Write(_toSend); + if (_useHex) + { + byte[] bytes = _toSend.Split(' ').Select(s => Convert.ToByte(s, 16)).ToArray(); + _port.Write(bytes, 0, bytes.Length); + } + else + { + _port.Write(_toSend); + } // Read if (_command.notifyStatus()) @@ -86,6 +95,9 @@ private void parse() // Get the actual command to send _toSend = command[2]; + + // Do we have a HEX bit? + _useHex = (connection.Length >= 7 && connection[6] == "1"); } } } diff --git a/Action/XmrSubscriber.cs b/Action/XmrSubscriber.cs index d3c99886..dc766611 100644 --- a/Action/XmrSubscriber.cs +++ b/Action/XmrSubscriber.cs @@ -19,6 +19,7 @@ class XmrSubscriber // Members to stop the thread private bool _forceStop = false; + private ManualResetEvent _manualReset = new ManualResetEvent(false); /// /// Last Heartbeat packet received @@ -53,132 +54,259 @@ public ClientInfo ClientInfoForm } private ClientInfo _clientInfoForm; + /// + /// The MQ Poller + /// + private NetMQPoller _poller; + + /// + /// The Init Address + /// + private string _address; + /// /// Runs the agent /// public void Run() { - try + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Thread Started"), LogType.Info.ToString()); + + while (!_forceStop) { - // Check we have an address to connect to. - if (string.IsNullOrEmpty(ApplicationSettings.Default.XmrNetworkAddress)) - throw new Exception("Empty XMR Network Address"); + lock (_locker) + { + try + { + // If we are restarting, reset + _manualReset.Reset(); - // Get the Private Key - AsymmetricCipherKeyPair rsaKey = _hardwareKey.getXmrKey(); + // Check we have an address to connect to. + if (string.IsNullOrEmpty(ApplicationSettings.Default.XmrNetworkAddress)) + throw new Exception("Empty XMR Network Address"); - // Connect to XMR - using (SubscriberSocket socket = new SubscriberSocket()) - { - // Bind - socket.Connect(ApplicationSettings.Default.XmrNetworkAddress); - socket.Subscribe("H"); - socket.Subscribe(_hardwareKey.Channel); + // Cache the address for this socket (the setting may change outside). + _address = ApplicationSettings.Default.XmrNetworkAddress; - // Notify - _clientInfoForm.XmrSubscriberStatus = "Connected to " + ApplicationSettings.Default.XmrNetworkAddress; + // Get the Private Key + AsymmetricCipherKeyPair rsaKey = _hardwareKey.getXmrKey(); - while (!_forceStop) - { - lock (_locker) + // Connect to XMR + try { - try + // Create a Poller + _poller = new NetMQPoller(); + + // Create a Socket + using (SubscriberSocket socket = new SubscriberSocket()) { - NetMQMessage message = socket.ReceiveMultipartMessage(); + // Options + socket.Options.ReconnectInterval = TimeSpan.FromSeconds(5); + socket.Options.Linger = TimeSpan.FromSeconds(0); + + // Bind + socket.Connect(ApplicationSettings.Default.XmrNetworkAddress); + socket.Subscribe("H"); + socket.Subscribe(_hardwareKey.Channel); + + // Add Socket to Poller + _poller.Add(socket); + + // Bind to the receive ready event + socket.ReceiveReady += _socket_ReceiveReady; + + // Notify + _clientInfoForm.XmrSubscriberStatus = "Connected to " + ApplicationSettings.Default.XmrNetworkAddress + ". Waiting for messages."; + + // Sit and wait, processing messages, indefinitely or until we are interrupted. + _poller.Run(); + } + } + finally + { + _poller.Dispose(); + } + + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Socket Disconnected, waiting to reconnect."), LogType.Info.ToString()); + } + catch (TerminatingException terminatingEx) + { + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "NetMQ terminating: " + terminatingEx.Message), LogType.Audit.ToString()); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unable to Subscribe: " + e.Message), LogType.Info.ToString()); + _clientInfoForm.XmrSubscriberStatus = e.Message; + } + + // Update status + _clientInfoForm.XmrSubscriberStatus = "Disconnected, waiting to reconnect, last activity: " + LastHeartBeat.ToString(); + + // Sleep for 60 seconds. + _manualReset.WaitOne(60 * 1000); + } + } + + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Subscriber Stopped"), LogType.Info.ToString()); + } + + /// + /// Receive event + /// + /// + /// + private void _socket_ReceiveReady(object sender, NetMQSocketEventArgs e) + { + try + { + processMessage(e.Socket.ReceiveMultipartMessage(), _hardwareKey.getXmrKey()); + } + catch (NetMQException netMQException) + { + throw netMQException; + } + catch (Exception ex) + { + // Log this message, but dont abort the thread + Trace.WriteLine(new LogMessage("XmrSubscriber - _socket_ReceiveReady", "Exception in Run: " + ex.Message), LogType.Error.ToString()); + Trace.WriteLine(new LogMessage("XmrSubscriber - _socket_ReceiveReady", e.ToString()), LogType.Audit.ToString()); + _clientInfoForm.XmrSubscriberStatus = "Error. " + ex.Message; + } + } - // Update status - string statusMessage = "Connected (" + ApplicationSettings.Default.XmrNetworkAddress + "), last activity: " + DateTime.Now.ToString(); + /// + /// Wait for a Message + /// + private void processMessage(NetMQMessage message, AsymmetricCipherKeyPair rsaKey) + { + // Update status + string statusMessage = "Connected (" + ApplicationSettings.Default.XmrNetworkAddress + "), last activity: " + DateTime.Now.ToString(); - // Write this out to a log - _clientInfoForm.XmrSubscriberStatus = statusMessage; - Trace.WriteLine(new LogMessage("XmrSubscriber - Run", statusMessage), LogType.Audit.ToString()); + // Write this out to a log + _clientInfoForm.XmrSubscriberStatus = statusMessage; + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", statusMessage), LogType.Audit.ToString()); - // Deal with heart beat - if (message[0].ConvertToString() == "H") - { - LastHeartBeat = DateTime.Now; - continue; - } + // Deal with heart beat + if (message[0].ConvertToString() == "H") + { + LastHeartBeat = DateTime.Now; + return; + } - // Decrypt the message - string opened = OpenSslInterop.decrypt(message[2].ConvertToString(), message[1].ConvertToString(), rsaKey.Private); + // Decrypt the message + string opened; + try + { + opened = OpenSslInterop.decrypt(message[2].ConvertToString(), message[1].ConvertToString(), rsaKey.Private); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("XmrSubscriber - processMessage", "Unopenable Message: " + e.Message), LogType.Error.ToString()); + Trace.WriteLine(new LogMessage("XmrSubscriber - processMessage", e.ToString()), LogType.Audit.ToString()); + return; + } - // Decode into a JSON string - PlayerAction action = JsonConvert.DeserializeObject(opened); + // Decode into a JSON string + PlayerAction action = JsonConvert.DeserializeObject(opened); - // Make sure the TTL hasn't expired - if (DateTime.Now > action.createdDt.AddSeconds(action.ttl)) - { - Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Expired Message: " + action.action), LogType.Info.ToString()); - continue; - } + // Make sure the TTL hasn't expired + if (DateTime.Now > action.createdDt.AddSeconds(action.ttl)) + { + Trace.WriteLine(new LogMessage("XmrSubscriber - processMessage", "Expired Message: " + action.action), LogType.Info.ToString()); + return; + } - // Decide what to do with the message, probably raise events according to the type of message we have - switch (action.action) - { - case "commandAction": + // Decide what to do with the message, probably raise events according to the type of message we have + switch (action.action) + { + case "commandAction": - // Create a schedule command out of the message - Dictionary obj = JsonConvert.DeserializeObject>(opened); - ScheduleCommand command = new ScheduleCommand(); - string code; - obj.TryGetValue("commandCode", out code); - command.Code = code; + // Create a schedule command out of the message + Dictionary obj = JsonConvert.DeserializeObject>(opened); + ScheduleCommand command = new ScheduleCommand(); + string code; + obj.TryGetValue("commandCode", out code); + command.Code = code; - new Thread(new ThreadStart(command.Run)).Start(); - break; + new Thread(new ThreadStart(command.Run)).Start(); + break; - case "collectNow": - case RevertToSchedulePlayerAction.Name: - if (OnAction != null) - OnAction(action); - break; + case "collectNow": + case RevertToSchedulePlayerAction.Name: + if (OnAction != null) + OnAction(action); + break; - case LayoutChangePlayerAction.Name: + case LayoutChangePlayerAction.Name: - LayoutChangePlayerAction changeLayout = JsonConvert.DeserializeObject(opened); + LayoutChangePlayerAction changeLayout = JsonConvert.DeserializeObject(opened); - if (OnAction != null) - OnAction(changeLayout); + if (OnAction != null) + OnAction(changeLayout); - break; + break; - case OverlayLayoutPlayerAction.Name: - OverlayLayoutPlayerAction overlayLayout = JsonConvert.DeserializeObject(opened); + case OverlayLayoutPlayerAction.Name: + OverlayLayoutPlayerAction overlayLayout = JsonConvert.DeserializeObject(opened); - if (OnAction != null) - OnAction(overlayLayout); - break; + if (OnAction != null) + OnAction(overlayLayout); + break; - case "screenShot": - ScreenShot.TakeAndSend(); - _clientInfoForm.notifyStatusToXmds(); - break; + case "screenShot": + ScreenShot.TakeAndSend(); + _clientInfoForm.notifyStatusToXmds(); + break; - default: - Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unknown Message: " + action.action), LogType.Info.ToString()); - break; - } - } - catch (Exception ex) - { - // Log this message, but dont abort the thread - Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString()); - _clientInfoForm.XmrSubscriberStatus = "Error. " + ex.Message; - } - } - } + default: + Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unknown Message: " + action.action), LogType.Info.ToString()); + break; + } + } + + /// + /// Wake Up + /// + public void Restart() + { + try + { + // Stop the poller + if (_poller != null) + { + _poller.Stop(); + } + + // Wakeup + _manualReset.Set(); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("XmrSubscriber - Restart", "Unable to Restart XMR: " + e.Message), LogType.Info.ToString()); + } + } + + /// + /// Stop the agent + /// + public void Stop() + { + try + { + // Stop the poller + if (_poller != null) + { + _poller.Stop(); } - // Update status - _clientInfoForm.XmrSubscriberStatus = "Not Running, last activity: " + LastHeartBeat.ToString(); + // Stop the thread at the next loop + _forceStop = true; - Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Subscriber Stopped"), LogType.Info.ToString()); + // Wakeup + _manualReset.Set(); } catch (Exception e) { - Trace.WriteLine(new LogMessage("XmrSubscriber - Run", "Unable to Subscribe to XMR: " + e.Message), LogType.Info.ToString()); - _clientInfoForm.XmrSubscriberStatus = e.Message; + Trace.WriteLine(new LogMessage("XmrSubscriber - Stop", "Unable to Stop XMR: " + e.Message), LogType.Info.ToString()); } } } diff --git a/Log/LogMessage.cs b/Log/LogMessage.cs index a85b9a43..e54ad2fe 100644 --- a/Log/LogMessage.cs +++ b/Log/LogMessage.cs @@ -97,7 +97,7 @@ public override string ToString() // Just do this with a string builder rather than an XML builder. String theMessage; - theMessage = String.Format("{0}", LogDate); + theMessage = String.Format("{0}", LogDate.ToString("yyyy-MM-dd HH:mm:ss")); theMessage += String.Format("{0}", _thread); theMessage += String.Format("{0}", _method); theMessage += String.Format("{0}", SecurityElement.Escape(_message)); diff --git a/Logic/ApplicationSettings.cs b/Logic/ApplicationSettings.cs index 96843cf3..aa09be25 100644 --- a/Logic/ApplicationSettings.cs +++ b/Logic/ApplicationSettings.cs @@ -40,9 +40,9 @@ public class ApplicationSettings private List _globalProperties; // Application Specific Settings we want to protect - private string _clientVersion = "1.8.1"; + private string _clientVersion = "1.8.2"; private string _version = "5"; - private int _clientCodeVersion = 128; + private int _clientCodeVersion = 129; public string ClientVersion { get { return _clientVersion; } } public string Version { get { return _version; } } @@ -498,6 +498,7 @@ public bool InDownloadWindow public int CollectInterval { get; set; } public int MaxConcurrentDownloads { get; set; } public int ScreenShotRequestInterval { get; set; } + public int ScreenShotSize { get; set; } private int _maxLogFileUploads; public int MaxLogFileUploads { get { return ((_maxLogFileUploads == 0) ? 10 : _maxLogFileUploads); } set { _maxLogFileUploads = value; } } diff --git a/Logic/Schedule.cs b/Logic/Schedule.cs index 1848185b..a0520d28 100644 --- a/Logic/Schedule.cs +++ b/Logic/Schedule.cs @@ -273,6 +273,10 @@ void _scheduleManager_OnRefreshSchedule() /// void _scheduleManager_OnScheduleManagerCheckComplete() { + // XMR address is present and has received at least 1 heart beat + bool xmrShouldBeRunning = (!string.IsNullOrEmpty(ApplicationSettings.Default.XmrNetworkAddress) && _xmrSubscriber.LastHeartBeat != DateTime.MinValue); + + // If the agent threads are all alive, and either XMR shouldn't be running OR the subscriber thread is alive. if (agentThreadsAlive()) { // Update status marker on the main thread. @@ -280,31 +284,23 @@ void _scheduleManager_OnScheduleManagerCheckComplete() } else { - Trace.WriteLine(new LogMessage("Schedule - OnScheduleManagerCheckComplete", "Agent threads are dead, not updating status.json"), LogType.Error.ToString()); + Trace.WriteLine(new LogMessage("Schedule - OnScheduleManagerCheckComplete", "Agent threads/XMR is dead, not updating status.json"), LogType.Error.ToString()); } - - try + + // Log for overdue XMR + if (xmrShouldBeRunning && _xmrSubscriber.LastHeartBeat < DateTime.Now.AddHours(-1)) { - // See if XMR should be running - if (!string.IsNullOrEmpty(ApplicationSettings.Default.XmrNetworkAddress) && _xmrSubscriber.LastHeartBeat != DateTime.MinValue) - { - // Log when severly overdue a check - if (_xmrSubscriber.LastHeartBeat < DateTime.Now.AddHours(-1)) - { - Trace.WriteLine(new LogMessage("Schedule - OnScheduleManagerCheckComplete", "XMR heart beat last received over an hour ago.")); - } + _clientInfoForm.XmrSubscriberStatus = "Long term Inactive (" + ApplicationSettings.Default.XmrNetworkAddress + "), last activity: " + _xmrSubscriber.LastHeartBeat.ToString(); + Trace.WriteLine(new LogMessage("Schedule - OnScheduleManagerCheckComplete", "XMR heart beat last received over an hour ago.")); - // Check to see if the last update date was over 5 minutes ago - if (_xmrSubscriber.LastHeartBeat < DateTime.Now.AddMinutes(-5)) - { - // Reconfigure it - _registerAgent_OnXmrReconfigure(); - } - } + // Issue an XMR restart if we've gone this long without connecting + // we do this because we suspect that the TCP socket has died without notifying the poller + restartXmr(); } - catch (Exception e) + else if (xmrShouldBeRunning && _xmrSubscriber.LastHeartBeat < DateTime.Now.AddMinutes(-5)) { - Trace.WriteLine(new LogMessage("Schedule - OnScheduleManagerCheckComplete", "Error = " + e.Message), LogType.Error.ToString()); + _clientInfoForm.XmrSubscriberStatus = "Inactive (" + ApplicationSettings.Default.XmrNetworkAddress + "), last activity: " + _xmrSubscriber.LastHeartBeat.ToString(); + Trace.WriteLine(new LogMessage("Schedule - OnScheduleManagerCheckComplete", "XMR heart beat last received over 5 minutes ago."), LogType.Audit.ToString()); } } @@ -317,7 +313,8 @@ private bool agentThreadsAlive() return _registerAgentThread.IsAlive && _scheduleAndRfAgentThread.IsAlive && _logAgentThread.IsAlive && - _libraryAgentThread.IsAlive; + _libraryAgentThread.IsAlive && + _xmrSubscriberThread.IsAlive; } /// @@ -325,34 +322,7 @@ private bool agentThreadsAlive() /// void _registerAgent_OnXmrReconfigure() { - try - { - // Stop and start the XMR thread - if (_xmrSubscriberThread != null && _xmrSubscriberThread.IsAlive) - { - _xmrSubscriberThread.Abort(); - } - } - catch (Exception e) - { - Trace.WriteLine(new LogMessage("Schedule - OnXmrReconfigure", "Unable to abort Subscriber. " + e.Message), LogType.Error.ToString()); - } - - try - { - // Reassert the hardware key, incase its changed at all - _xmrSubscriber.HardwareKey = _hardwareKey; - - // Start the thread again - _xmrSubscriberThread = new Thread(new ThreadStart(_xmrSubscriber.Run)); - _xmrSubscriberThread.Name = "XmrSubscriber"; - - _xmrSubscriberThread.Start(); - } - catch (Exception e) - { - Trace.WriteLine(new LogMessage("Schedule - OnXmrReconfigure", "Unable to start Subscriber. " + e.Message), LogType.Error.ToString()); - } + restartXmr(); } /// @@ -438,6 +408,22 @@ public void wakeUpXmds() _logAgent.WakeUp(); } + /// + /// Restart XMR + /// + public void restartXmr() + { + try + { + // Stop and start the XMR thread + _xmrSubscriber.Restart(); + } + catch (Exception e) + { + Trace.WriteLine(new LogMessage("Schedule - restartXmr", "Unable to restart XMR: " + e.Message), LogType.Error.ToString()); + } + } + /// /// Moves the layout on /// @@ -604,7 +590,10 @@ public void Stop() _logAgent.Stop(); // Stop the subsriber thread - _xmrSubscriberThread.Abort(); + _xmrSubscriber.Stop(); + + // Clean up any NetMQ sockets, etc (false means don't block). + NetMQ.NetMQConfig.Cleanup(false); // Stop the embedded server _server.Stop(); diff --git a/Logic/ScheduleManager.cs b/Logic/ScheduleManager.cs index 24532b02..9d810afa 100644 --- a/Logic/ScheduleManager.cs +++ b/Logic/ScheduleManager.cs @@ -257,10 +257,6 @@ public void Run() } } } - - // Write a flag to the status.xml file - if (OnScheduleManagerCheckComplete != null) - OnScheduleManagerCheckComplete(); } catch (Exception ex) { @@ -271,7 +267,8 @@ public void Run() } // Completed this check - OnScheduleManagerCheckComplete(); + if (OnScheduleManagerCheckComplete != null) + OnScheduleManagerCheckComplete(); // Sleep this thread for 10 seconds _manualReset.WaitOne(10 * 1000); @@ -286,6 +283,9 @@ public void Run() /// private bool IsNewScheduleAvailable() { + // Remove completed change actions + removeLayoutChangeActionIfComplete(); + // Remove completed overlay actions removeOverlayLayoutActionIfComplete(); @@ -789,8 +789,10 @@ private void LoadScheduleFromLayoutChangeActions() if (action.downloadRequired) continue; + DateTime actionCreateDt = DateTime.Parse(action.createdDt); + ScheduleItem item = new ScheduleItem(); - item.FromDt = DateTime.MinValue; + item.FromDt = actionCreateDt.AddSeconds(-1); item.ToDt = DateTime.MaxValue; item.id = action.layoutId; item.scheduleid = 0; @@ -946,6 +948,9 @@ private string LayoutsInSchedule() foreach (ScheduleItem layoutSchedule in CurrentSchedule) { + if (layoutSchedule.Override) + layoutsInSchedule += "API Action "; + layoutsInSchedule += "LayoutId: " + layoutSchedule.id + ". Runs from " + layoutSchedule.FromDt.ToString() + Environment.NewLine; } @@ -1018,6 +1023,22 @@ public bool removeLayoutChangeActionIfComplete(ScheduleItem item) return false; } + /// + /// Remove Layout Change actions if they have completed + /// + public void removeLayoutChangeActionIfComplete() + { + // Check every action to see if complete + foreach (LayoutChangePlayerAction action in _layoutChangeActions) + { + if (action.IsServiced()) + { + _layoutChangeActions.Remove(action); + RefreshSchedule = true; + } + } + } + /// /// Add an overlay layout action /// diff --git a/Logic/ScreenShot.cs b/Logic/ScreenShot.cs index 9d3c2845..2a221359 100644 --- a/Logic/ScreenShot.cs +++ b/Logic/ScreenShot.cs @@ -34,18 +34,49 @@ public static void TakeAndSend() g.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy); } - using (MemoryStream stream = new MemoryStream()) + // Resize? + if (ApplicationSettings.Default.ScreenShotSize != 0) { - bitmap.Save(stream, ImageFormat.Jpeg); + Size thumbSize; + double ratio = (double)bounds.Width / (double)bounds.Height; - byte[] bytes = stream.ToArray(); - - using (xmds.xmds screenShotXmds = new xmds.xmds()) + if (bounds.Width > bounds.Height) { - screenShotXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; - screenShotXmds.SubmitScreenShotCompleted += screenShotXmds_SubmitScreenShotCompleted; - screenShotXmds.SubmitScreenShotAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, bytes); + // Landscape + thumbSize = new Size(ApplicationSettings.Default.ScreenShotSize, (int)(ApplicationSettings.Default.ScreenShotSize / ratio)); } + else + { + // Portrait + thumbSize = new Size((int)(ApplicationSettings.Default.ScreenShotSize * ratio), ApplicationSettings.Default.ScreenShotSize); + } + + // Create a bitmap at our desired resolution + using (Bitmap thumb = new Bitmap(bitmap, thumbSize.Width, thumbSize.Height)) + { + send(thumb); + } + } + else + { + send(bitmap); + } + } + } + + private static void send(Bitmap bitmap) + { + using (MemoryStream stream = new MemoryStream()) + { + bitmap.Save(stream, ImageFormat.Jpeg); + + byte[] bytes = stream.ToArray(); + + using (xmds.xmds screenShotXmds = new xmds.xmds()) + { + screenShotXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; + screenShotXmds.SubmitScreenShotCompleted += screenShotXmds_SubmitScreenShotCompleted; + screenShotXmds.SubmitScreenShotAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, bytes); } } } diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 76d8e804..938e014a 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -11,7 +11,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Xibo Digital Signage")] [assembly: AssemblyProduct("Xibo")] -[assembly: AssemblyCopyright("Copyright Dan Garner © 2008-2016")] +[assembly: AssemblyCopyright("Copyright Dan Garner © 2008-2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -30,6 +30,6 @@ // Build Number // Revision // -[assembly: AssemblyVersion("10.8.1.0")] -[assembly: AssemblyFileVersion("10.8.1.0")] +[assembly: AssemblyVersion("10.8.2.0")] +[assembly: AssemblyFileVersion("10.8.2.0")] [assembly: NeutralResourcesLanguageAttribute("en-GB")] diff --git a/XiboClient.csproj b/XiboClient.csproj index c9ec5e03..9fc296e1 100644 --- a/XiboClient.csproj +++ b/XiboClient.csproj @@ -103,12 +103,11 @@ packages\NetMQ.4.0.0.1\lib\net40\NetMQ.dll True - - packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll - True + + packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll - - packages\NodaTime.1.3.2\lib\net35-Client\NodaTime.dll + + packages\NodaTime.2.0.2\lib\net45\NodaTime.dll True @@ -117,13 +116,17 @@ + + - - False - packages\EmbedIO.1.1.1\lib\net452\Unosquare.Labs.EmbedIO.dll + + packages\EmbedIO.1.6.9\lib\net452\Unosquare.Labs.EmbedIO.dll + + + packages\Unosquare.Swan.0.14.2\lib\net452\Unosquare.Swan.dll diff --git a/XmdsAgents/RegisterAgent.cs b/XmdsAgents/RegisterAgent.cs index f5c4eaa7..93fbbb7d 100644 --- a/XmdsAgents/RegisterAgent.cs +++ b/XmdsAgents/RegisterAgent.cs @@ -223,16 +223,16 @@ private string WindowsToIana(string windowsZoneId) if (windowsZoneId.Equals("UTC", StringComparison.Ordinal)) return "Etc/UTC"; - var tzdbSource = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default; - var tzi = TimeZoneInfo.FindSystemTimeZoneById(windowsZoneId); - if (tzi == null) - return null; - - var tzid = tzdbSource.MapTimeZoneId(tzi); - if (tzid == null) - return null; - - return tzdbSource.CanonicalIdMap[tzid]; + var source = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default; + string result; + // If there's no such mapping, result will be null. + source.WindowsMapping.PrimaryMapping.TryGetValue(windowsZoneId, out result); + // Canonicalize + if (result != null) + { + result = source.CanonicalIdMap[result]; + } + return result; } } } diff --git a/default.config.xml b/default.config.xml index e438b2e7..edcc42e3 100644 --- a/default.config.xml +++ b/default.config.xml @@ -52,4 +52,5 @@ 1 9696 + 0 \ No newline at end of file diff --git a/packages.config b/packages.config index da04f453..0e43a549 100644 --- a/packages.config +++ b/packages.config @@ -2,8 +2,9 @@ - + - - + + + \ No newline at end of file