2
* Xibo - Digitial Signage - http://www.xibo.org.uk
3
* Copyright (C) 2006,2007,2008 Daniel Garner and James Packer
5
* This file is part of Xibo.
7
* Xibo is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU Affero General Public License as published by
9
* the Free Software Foundation, either version 3 of the License, or
12
* Xibo is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU Affero General Public License for more details.
17
* You should have received a copy of the GNU Affero General Public License
18
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
21
using System.Collections.Generic;
22
using System.Collections.ObjectModel;
23
using System.Security.Cryptography;
26
using System.Windows.Forms;
28
using System.Xml.Serialization;
29
using System.Diagnostics;
34
/// Reads the schedule
38
public delegate void ScheduleChangeDelegate(string layoutPath, int scheduleId, int layoutId);
39
public event ScheduleChangeDelegate ScheduleChangeEvent;
41
private Collection<LayoutSchedule> layoutSchedule;
42
private int currentLayout = 0;
43
private string scheduleLocation;
46
private XiboClient.xmds.xmds xmds2;
47
private bool xmdsProcessing;
48
private bool forceChange = false;
51
private HardwareKey hardwareKey;
54
private CacheManager _cacheManager;
59
/// <param name="scheduleLocation"></param>
60
public Schedule(string scheduleLocation, ref CacheManager cacheManager)
62
// Save the schedule location
63
this.scheduleLocation = scheduleLocation;
65
// Create a new collection for the layouts in the schedule
66
layoutSchedule = new Collection<LayoutSchedule>();
69
_cacheManager = cacheManager;
71
// Create a new Xmds service object
72
xmds2 = new XiboClient.xmds.xmds();
76
/// Initialize the Schedule components
78
public void InitializeComponents()
81
// Parse and Load the Schedule into the Collection
85
// Get the key for this display
86
hardwareKey = new HardwareKey();
89
// Start up the Xmds Service Object
91
this.xmds2.Credentials = null;
92
this.xmds2.Url = Properties.Settings.Default.XiboClient_xmds_xmds;
93
this.xmds2.UseDefaultCredentials = false;
95
xmdsProcessing = false;
96
xmds2.RequiredFilesCompleted += new XiboClient.xmds.RequiredFilesCompletedEventHandler(xmds2_RequiredFilesCompleted);
97
xmds2.ScheduleCompleted += new XiboClient.xmds.ScheduleCompletedEventHandler(xmds2_ScheduleCompleted);
99
System.Diagnostics.Trace.WriteLine(String.Format("Collection Interval: {0}", Properties.Settings.Default.collectInterval), "Schedule - InitializeComponents");
101
// The Timer for the Service call
103
Timer xmdsTimer = new Timer();
104
xmdsTimer.Interval = (int) Properties.Settings.Default.collectInterval * 1000;
105
xmdsTimer.Tick += new EventHandler(xmdsTimer_Tick);
109
xmdsProcessing = true;
111
// Fire off a get required files event - async
112
xmds2.RequiredFilesAsync(Properties.Settings.Default.ServerKey, hardwareKey.Key, Properties.Settings.Default.Version);
115
void xmds2_RequiredFilesCompleted(object sender, XiboClient.xmds.RequiredFilesCompletedEventArgs e)
117
System.Diagnostics.Debug.WriteLine("RequiredFilesAsync complete.", "Schedule - RequiredFilesCompleted");
119
//Dont let this effect the rendering
120
Application.DoEvents();
124
// There was an error - what do we do?
125
System.Diagnostics.Trace.WriteLine(new LogMessage("Schedule - RequiredFilesCompleted", e.Error.Message), LogType.Error.ToString());
127
// Is it a "not licensed" error
128
if (e.Error.Message == "This display client is not licensed")
130
Properties.Settings.Default.licensed = 0;
133
xmdsProcessing = false;
137
// Set the flag to indicate we have a connection to XMDS
138
Properties.Settings.Default.XmdsLastConnection = DateTime.Now;
140
// Firstly we know we are licensed if we get this far
141
if (Properties.Settings.Default.licensed == 0)
143
Properties.Settings.Default.licensed = 1;
148
// Load the result into XML
149
FileCollector fileCollector = new FileCollector(_cacheManager, e.Result);
151
// Bind some events that the fileCollector will raise
152
fileCollector.LayoutFileChanged += new FileCollector.LayoutFileChangedDelegate(fileCollector_LayoutFileChanged);
153
fileCollector.CollectionComplete += new FileCollector.CollectionCompleteDelegate(fileCollector_CollectionComplete);
154
fileCollector.MediaFileChanged += new FileCollector.MediaFileChangedDelegate(fileCollector_MediaFileChanged);
156
fileCollector.CompareAndCollect();
160
xmdsProcessing = false;
163
System.Diagnostics.Trace.WriteLine(new LogMessage("Schedule - RequiredFilesCompleted", "Error Comparing and Collecting: " + ex.Message), LogType.Error.ToString());
166
_cacheManager.WriteCacheManager();
170
void fileCollector_MediaFileChanged(string path)
172
System.Diagnostics.Debug.WriteLine("Media file changed");
176
void fileCollector_CollectionComplete()
178
System.Diagnostics.Debug.WriteLine("File Collector Complete - getting Schedule.");
180
// All the files have been collected, so we want to update the schedule (do we want to send off a MD5 of the schedule?)
181
xmds2.ScheduleAsync(Properties.Settings.Default.ServerKey, hardwareKey.Key, Properties.Settings.Default.Version);
184
void xmds2_ScheduleCompleted(object sender, XiboClient.xmds.ScheduleCompletedEventArgs e)
186
System.Diagnostics.Debug.WriteLine("Schedule Retrival Complete.");
188
// Set XMDS to no longer be processing
189
xmdsProcessing = false;
191
// Expect new schedule XML
194
//There was an error - what do we do?
195
System.Diagnostics.Trace.WriteLine(e.Error.Message);
199
// Only update the schedule if its changed.
200
String md5CurrentSchedule = "";
202
// Set the flag to indicate we have a connection to XMDS
203
Properties.Settings.Default.XmdsLastConnection = DateTime.Now;
207
StreamReader sr = new StreamReader(File.Open(this.scheduleLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite));
209
// Yes - get the MD5 of it, and compare to the MD5 of the file in the XML
210
md5CurrentSchedule = Hashes.MD5(sr.ReadToEnd());
216
System.Diagnostics.Debug.WriteLine(ex.Message);
219
// Hash of the result
220
String md5NewSchedule = Hashes.MD5(e.Result);
222
if (md5CurrentSchedule == md5NewSchedule) return;
224
System.Diagnostics.Debug.WriteLine("Different Schedules Detected, writing new schedule.", "Schedule - ScheduleCompleted");
226
// Write the result to the schedule xml location
227
StreamWriter sw = new StreamWriter(this.scheduleLocation, false, Encoding.UTF8);
232
System.Diagnostics.Debug.WriteLine("New Schedule Recieved", "xmds_ScheduleCompleted");
234
// The schedule has been updated with new information.
235
// We could improve the logic here, perhaps generating a new layoutSchedule collection and comparing the two before we destroy this one..
236
layoutSchedule.Clear();
242
void fileCollector_LayoutFileChanged(string layoutPath)
244
System.Diagnostics.Debug.WriteLine("Layout file changed");
246
// If the layout that got changed is the current layout, move on
249
if (layoutSchedule[currentLayout].layoutFile == Properties.Settings.Default.LibraryPath + @"\" + layoutPath)
257
System.Diagnostics.Trace.WriteLine(new LogMessage("fileCollector_LayoutFileChanged", String.Format("Unable to determine current layout with exception {0}", ex.Message)), LogType.Error.ToString());
261
void xmdsTimer_Tick(object sender, EventArgs e)
264
// Ticks every "collectInterval"
267
System.Diagnostics.Debug.WriteLine("Collection Timer Ticked, but previous request still active", "XmdsTicker");
272
Application.DoEvents(); // Make sure everything that is queued to render does
274
xmdsProcessing = true;
276
System.Diagnostics.Debug.WriteLine("Collection Timer Ticked, Firing RequiredFilesAsync");
278
// Fire off a get required files event - async
279
xmds2.RequiredFilesAsync(Properties.Settings.Default.ServerKey, hardwareKey.Key, Properties.Settings.Default.Version);
283
System.Diagnostics.Trace.Flush();
287
/// Moves the layout on
289
public void NextLayout()
291
int previousLayout = currentLayout;
293
//increment the current layout
296
//if the current layout is greater than the count of layouts, then reset to 0
297
if (currentLayout >= layoutSchedule.Count)
302
if (layoutSchedule.Count == 1 && !forceChange)
304
Debug.WriteLine(new LogMessage("Schedule - NextLayout", "Only 1 layout showing, refreshing it"), LogType.Info.ToString());
307
System.Diagnostics.Debug.WriteLine(String.Format("Next layout: {0}", layoutSchedule[currentLayout].layoutFile), "Schedule - Next Layout");
312
ScheduleChangeEvent(layoutSchedule[currentLayout].layoutFile, layoutSchedule[currentLayout].scheduleid, layoutSchedule[currentLayout].id);
316
/// Gets the schedule from the schedule location
317
/// If the schedule location doesn't exist - use the default.xml (how to we guarentee that the default.xml exists?)
318
/// If layouts in the schedule file dont exist, then ignore them - if none of them exist then add a default one?
322
XmlDocument scheduleXml;
324
// Check the schedule file exists
325
if (File.Exists(scheduleLocation))
327
// Read the schedule file
328
XmlReader reader = XmlReader.Create(scheduleLocation);
330
scheduleXml = new XmlDocument();
331
scheduleXml.Load(reader);
337
// Use the default XML
338
scheduleXml = new XmlDocument();
339
scheduleXml.LoadXml("<schedule></schedule>");
342
// Get the layouts in this schedule
343
XmlNodeList listLayouts = scheduleXml.SelectNodes("/schedule/layout");
346
if (listLayouts.Count == 0)
348
// Schedule up the default
349
LayoutSchedule temp = new LayoutSchedule();
350
temp.layoutFile = Properties.Settings.Default.LibraryPath + @"\Default.xml";
354
layoutSchedule.Add(temp);
358
// Get them and add to collection
359
foreach (XmlNode layout in listLayouts)
361
XmlAttributeCollection attributes = layout.Attributes;
363
string layoutFile = attributes["file"].Value;
364
string replace = ".xml";
365
layoutFile = layoutFile.TrimEnd(replace.ToCharArray());
367
string scheduleId = "";
368
if (attributes["scheduleid"] != null) scheduleId = attributes["scheduleid"].Value;
370
LayoutSchedule temp = new LayoutSchedule();
371
temp.layoutFile = Properties.Settings.Default.LibraryPath + @"\" + layoutFile + @".xlf";
372
temp.id = int.Parse(layoutFile);
374
if (scheduleId != "") temp.scheduleid = int.Parse(scheduleId);
376
layoutSchedule.Add(temp);
385
ScheduleChangeEvent(layoutSchedule[0].layoutFile, layoutSchedule[0].scheduleid, layoutSchedule[0].id);
390
/// The number of active layouts in the current schedule
392
public int ActiveLayouts
396
return layoutSchedule.Count;
404
public struct LayoutSchedule
406
public string layoutFile;
408
public int scheduleid;
2
* Xibo - Digitial Signage - http://www.xibo.org.uk
3
* Copyright (C) 2006,2007,2008 Daniel Garner and James Packer
5
* This file is part of Xibo.
7
* Xibo is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU Affero General Public License as published by
9
* the Free Software Foundation, either version 3 of the License, or
12
* Xibo is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU Affero General Public License for more details.
17
* You should have received a copy of the GNU Affero General Public License
18
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
21
using System.Collections.Generic;
22
using System.Collections.ObjectModel;
23
using System.Security.Cryptography;
26
using System.Windows.Forms;
28
using System.Xml.Serialization;
29
using System.Diagnostics;
34
/// Reads the schedule
38
public delegate void ScheduleChangeDelegate(string layoutPath, int scheduleId, int layoutId);
39
public event ScheduleChangeDelegate ScheduleChangeEvent;
41
private Collection<LayoutSchedule> layoutSchedule;
42
private int currentLayout = 0;
43
private string scheduleLocation;
46
private XiboClient.xmds.xmds xmds2;
47
private bool xmdsProcessing;
48
private bool forceChange = false;
51
private HardwareKey hardwareKey;
54
private CacheManager _cacheManager;
59
/// <param name="scheduleLocation"></param>
60
public Schedule(string scheduleLocation, ref CacheManager cacheManager)
62
// Save the schedule location
63
this.scheduleLocation = scheduleLocation;
65
// Create a new collection for the layouts in the schedule
66
layoutSchedule = new Collection<LayoutSchedule>();
69
_cacheManager = cacheManager;
71
// Create a new Xmds service object
72
xmds2 = new XiboClient.xmds.xmds();
76
/// Initialize the Schedule components
78
public void InitializeComponents()
81
// Parse and Load the Schedule into the Collection
85
// Get the key for this display
86
hardwareKey = new HardwareKey();
89
// Start up the Xmds Service Object
91
this.xmds2.Credentials = null;
92
this.xmds2.Url = Properties.Settings.Default.XiboClient_xmds_xmds;
93
this.xmds2.UseDefaultCredentials = false;
95
xmdsProcessing = false;
96
xmds2.RequiredFilesCompleted += new XiboClient.xmds.RequiredFilesCompletedEventHandler(xmds2_RequiredFilesCompleted);
97
xmds2.ScheduleCompleted += new XiboClient.xmds.ScheduleCompletedEventHandler(xmds2_ScheduleCompleted);
99
System.Diagnostics.Trace.WriteLine(String.Format("Collection Interval: {0}", Properties.Settings.Default.collectInterval), "Schedule - InitializeComponents");
101
// The Timer for the Service call
103
Timer xmdsTimer = new Timer();
104
xmdsTimer.Interval = (int) Properties.Settings.Default.collectInterval * 1000;
105
xmdsTimer.Tick += new EventHandler(xmdsTimer_Tick);
109
xmdsProcessing = true;
111
// Fire off a get required files event - async
112
xmds2.RequiredFilesAsync(Properties.Settings.Default.ServerKey, hardwareKey.Key, Properties.Settings.Default.Version);
115
void xmds2_RequiredFilesCompleted(object sender, XiboClient.xmds.RequiredFilesCompletedEventArgs e)
117
System.Diagnostics.Debug.WriteLine("RequiredFilesAsync complete.", "Schedule - RequiredFilesCompleted");
119
//Dont let this effect the rendering
120
Application.DoEvents();
124
// There was an error - what do we do?
125
System.Diagnostics.Trace.WriteLine(new LogMessage("Schedule - RequiredFilesCompleted", e.Error.Message), LogType.Error.ToString());
127
// Is it a "not licensed" error
128
if (e.Error.Message == "This display client is not licensed")
130
Properties.Settings.Default.licensed = 0;
133
xmdsProcessing = false;
137
// Set the flag to indicate we have a connection to XMDS
138
Properties.Settings.Default.XmdsLastConnection = DateTime.Now;
140
// Firstly we know we are licensed if we get this far
141
if (Properties.Settings.Default.licensed == 0)
143
Properties.Settings.Default.licensed = 1;
148
// Load the result into XML
149
FileCollector fileCollector = new FileCollector(_cacheManager, e.Result);
151
// Bind some events that the fileCollector will raise
152
fileCollector.LayoutFileChanged += new FileCollector.LayoutFileChangedDelegate(fileCollector_LayoutFileChanged);
153
fileCollector.CollectionComplete += new FileCollector.CollectionCompleteDelegate(fileCollector_CollectionComplete);
154
fileCollector.MediaFileChanged += new FileCollector.MediaFileChangedDelegate(fileCollector_MediaFileChanged);
156
fileCollector.CompareAndCollect();
160
xmdsProcessing = false;
163
System.Diagnostics.Trace.WriteLine(new LogMessage("Schedule - RequiredFilesCompleted", "Error Comparing and Collecting: " + ex.Message), LogType.Error.ToString());
166
_cacheManager.WriteCacheManager();
170
void fileCollector_MediaFileChanged(string path)
172
System.Diagnostics.Debug.WriteLine("Media file changed");
176
void fileCollector_CollectionComplete()
178
System.Diagnostics.Debug.WriteLine("File Collector Complete - getting Schedule.");
180
// All the files have been collected, so we want to update the schedule (do we want to send off a MD5 of the schedule?)
181
xmds2.ScheduleAsync(Properties.Settings.Default.ServerKey, hardwareKey.Key, Properties.Settings.Default.Version);
184
void xmds2_ScheduleCompleted(object sender, XiboClient.xmds.ScheduleCompletedEventArgs e)
186
System.Diagnostics.Debug.WriteLine("Schedule Retrival Complete.");
188
// Set XMDS to no longer be processing
189
xmdsProcessing = false;
191
// Expect new schedule XML
194
//There was an error - what do we do?
195
System.Diagnostics.Trace.WriteLine(e.Error.Message);
199
// Only update the schedule if its changed.
200
String md5CurrentSchedule = "";
202
// Set the flag to indicate we have a connection to XMDS
203
Properties.Settings.Default.XmdsLastConnection = DateTime.Now;
207
StreamReader sr = new StreamReader(File.Open(this.scheduleLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite));
209
// Yes - get the MD5 of it, and compare to the MD5 of the file in the XML
210
md5CurrentSchedule = Hashes.MD5(sr.ReadToEnd());
216
System.Diagnostics.Debug.WriteLine(ex.Message);
219
// Hash of the result
220
String md5NewSchedule = Hashes.MD5(e.Result);
222
if (md5CurrentSchedule == md5NewSchedule) return;
224
System.Diagnostics.Debug.WriteLine("Different Schedules Detected, writing new schedule.", "Schedule - ScheduleCompleted");
226
// Write the result to the schedule xml location
227
StreamWriter sw = new StreamWriter(this.scheduleLocation, false, Encoding.UTF8);
232
System.Diagnostics.Debug.WriteLine("New Schedule Recieved", "xmds_ScheduleCompleted");
234
// The schedule has been updated with new information.
235
// We could improve the logic here, perhaps generating a new layoutSchedule collection and comparing the two before we destroy this one..
236
layoutSchedule.Clear();
242
void fileCollector_LayoutFileChanged(string layoutPath)
244
System.Diagnostics.Debug.WriteLine("Layout file changed");
246
// If the layout that got changed is the current layout, move on
249
if (layoutSchedule[currentLayout].layoutFile == Properties.Settings.Default.LibraryPath + @"\" + layoutPath)
257
System.Diagnostics.Trace.WriteLine(new LogMessage("fileCollector_LayoutFileChanged", String.Format("Unable to determine current layout with exception {0}", ex.Message)), LogType.Error.ToString());
261
void xmdsTimer_Tick(object sender, EventArgs e)
264
// Ticks every "collectInterval"
267
System.Diagnostics.Debug.WriteLine("Collection Timer Ticked, but previous request still active", "XmdsTicker");
272
Application.DoEvents(); // Make sure everything that is queued to render does
274
xmdsProcessing = true;
276
System.Diagnostics.Debug.WriteLine("Collection Timer Ticked, Firing RequiredFilesAsync");
278
// Fire off a get required files event - async
279
xmds2.RequiredFilesAsync(Properties.Settings.Default.ServerKey, hardwareKey.Key, Properties.Settings.Default.Version);
283
System.Diagnostics.Trace.Flush();
287
/// Moves the layout on
289
public void NextLayout()
291
int previousLayout = currentLayout;
293
//increment the current layout
296
//if the current layout is greater than the count of layouts, then reset to 0
297
if (currentLayout >= layoutSchedule.Count)
302
if (layoutSchedule.Count == 1 && !forceChange)
304
Debug.WriteLine(new LogMessage("Schedule - NextLayout", "Only 1 layout showing, refreshing it"), LogType.Info.ToString());
307
System.Diagnostics.Debug.WriteLine(String.Format("Next layout: {0}", layoutSchedule[currentLayout].layoutFile), "Schedule - Next Layout");
312
ScheduleChangeEvent(layoutSchedule[currentLayout].layoutFile, layoutSchedule[currentLayout].scheduleid, layoutSchedule[currentLayout].id);
316
/// Gets the schedule from the schedule location
317
/// If the schedule location doesn't exist - use the default.xml (how to we guarentee that the default.xml exists?)
318
/// If layouts in the schedule file dont exist, then ignore them - if none of them exist then add a default one?
322
XmlDocument scheduleXml;
324
// Check the schedule file exists
325
if (File.Exists(scheduleLocation))
327
// Read the schedule file
328
XmlReader reader = XmlReader.Create(scheduleLocation);
330
scheduleXml = new XmlDocument();
331
scheduleXml.Load(reader);
337
// Use the default XML
338
scheduleXml = new XmlDocument();
339
scheduleXml.LoadXml("<schedule></schedule>");
342
// Get the layouts in this schedule
343
XmlNodeList listLayouts = scheduleXml.SelectNodes("/schedule/layout");
346
if (listLayouts.Count == 0)
348
// Schedule up the default
349
LayoutSchedule temp = new LayoutSchedule();
350
temp.layoutFile = Properties.Settings.Default.LibraryPath + @"\Default.xml";
354
layoutSchedule.Add(temp);
358
// Get them and add to collection
359
foreach (XmlNode layout in listLayouts)
361
XmlAttributeCollection attributes = layout.Attributes;
363
string layoutFile = attributes["file"].Value;
364
string replace = ".xml";
365
layoutFile = layoutFile.TrimEnd(replace.ToCharArray());
367
string scheduleId = "";
368
if (attributes["scheduleid"] != null) scheduleId = attributes["scheduleid"].Value;
370
LayoutSchedule temp = new LayoutSchedule();
371
temp.layoutFile = Properties.Settings.Default.LibraryPath + @"\" + layoutFile + @".xlf";
372
temp.id = int.Parse(layoutFile);
374
if (scheduleId != "") temp.scheduleid = int.Parse(scheduleId);
376
layoutSchedule.Add(temp);
385
ScheduleChangeEvent(layoutSchedule[0].layoutFile, layoutSchedule[0].scheduleid, layoutSchedule[0].id);
390
/// The number of active layouts in the current schedule
392
public int ActiveLayouts
396
return layoutSchedule.Count;
404
public struct LayoutSchedule
406
public string layoutFile;
408
public int scheduleid;