I'm creating an RSS Ticker to be used on a bunch of displays thoughout the office. This RSS Ticker will run in tandom with a Twiter Feed reader, a weather widget and a clock, all in the same .fla.
As there are a ton of these displays, I don't want each one to go online for the rss, twitter and weather data. All of this data is contained within a number of simple XML files that get downloaded from the internet.
I've created a windows service that runs on our server. This service does all of the work as far as watching for updates, and downloading new data files to a share on our network. I then have the flash dashboards on all of the displays get their information from the network copies. That way the data is downloaded once, and everything else just accesses this local cache.
Everything works, but randomly the RSS ticker will stop working. I don't have any way to remote in to these displays to check their error logs, but I get the exact same issue on my local test environment when I unplug my ethernet cable. The dashboard tries to acces the network RSS copies, fails, and then continues to fail with each tick of a timer, even after the connection is reestablished.
I want to be able to gracefully wait out a disconnection, then restart the RSS ticker once the display reconnects. I have no clue how to do this. The following is my RSS related code:
// used to load a local xml file (stored in the same folder as the dashboard) that tells
// the dashboards which RSS feeds can be found on the network, and where they are located.
// It also contains the limits for how long each feed should be shown (both a time limit,
// and a maximimum number of feed items)
var rssListXMLLoader:URLLoader = new URLLoader();
rssListXMLLoader.addEventListener(Event.COMPLETE, rssListXMLLoaded);
rssListXMLLoader.addEventListener(IOErrorEvent.IO_ERROR, ioRSSListXMLLoaderErrorHandler);
// used to load the individual RRS feeds
var rssFeedXMLLoader:URLLoader = new URLLoader();
rssFeedXMLLoader.addEventListener(Event.COMPLETE, rssFeedXMLLoaded);
rssFeedXMLLoader.addEventListener(IOErrorEvent.IO_ERROR, ioRSSFeedXMLLoaderErrorHandler);
// rssListXMLData:XML and rssFeedXMLData:XML are used to store the XML data that is returned
// by the above loaders.
var rssListXMLData:XML = new XML();
var rssFeedXMLData:XML = new XML();
var currentRSSIndex:int = 2^10;
var currentFeedIndex:int = 2^10;
var currentLimit_Feeds:int = 2^10;
var currentLimit_Minutes:int = 2^10;
var limitStartTime:Number = new Date().time;
var gettingNewFeed = false;
// the blow Timer is used to keep the ticker moving. Each tick, it checks to see of the
// current RSS on sceen is has any text left. If it does, it removes the first letter
// causing the string to appear as if it is scrolling from right to left. If it has no
// more text, it gets the next feed.
var rssTickerTMR:Timer = new Timer(100, 0);
rssTickerTMR.addEventListener(TimerEvent.TIMER, updateRSSTicker);
rssTickerTMR.start();
updateRSSTicker();
function updateRSSTicker(e:Event = null):void
{
if(ins_rssContent.text.length == 0)
{
if(!gettingNewFeed)
{
gettingNewFeed = true;
getNewFeed();
}
}
else
{
ins_rssContent.text = ins_rssContent.text.substring(1);
}
}
// the below function checks to see if the RSS List is loaded. If it isn't it loads it,
// if it is already loaded, it calls the rssListXMLLoaded. This way, rssListXMLLoaded is
// never called unless the RSS List is already loaded.
function getNewFeed():void
{
if (rssListXMLData == "")
{
trace("Loading RSS List XML");
rssListXMLLoader.load(new URLRequest("rssFeeds.xml"));
}
else
{
rssListXMLLoaded();
}
}
// the below function manages which feed needs to be used from the list.
function rssListXMLLoaded(e:Event = null):void
{
if (e != null)
{
rssListXMLData = new XML(e.target.data);
}
currentFeedIndex++;
if (
currentFeedIndex >= rssFeedXMLData.channel["item"].length() ||
currentFeedIndex >= currentLimit_Feeds ||
new Date().time - limitStartTime >= (currentLimit_Minutes * 1000 * 60)
)
{
limitStartTime = new Date().time;
currentFeedIndex = 0;
currentRSSIndex++;
currentRSSIndex = (currentRSSIndex >= rssListXML.children().length()) ? 0 : currentRSSIndex;
currentLimit_Feeds = Number(rssListXMLData.RSSFeed[currentRSSIndex].@limitFeeds)
currentLimit_Minutes = Number(rssListXMLData.RSSFeed[currentRSSIndex].@limitMinutes)
}
try
{
rssFeedXMLLoader.load(new URLRequest(rssListXMLData.RSSFeed[currentRSSIndex]));
}
catch(e:Error)
{
trace("whoops, try again");
}
}
// the below function sets the text on the dashboard, and sets gettingNewfeed to false. This allows the
// rssTickerTMR:Timer to start removing the first letter of the newly added feed, causing the text to "scroll"
function rssFeedXMLLoaded(e:Event):void
{
rssFeedXMLData = new XML(e.target.data);
if (rssFeedXMLData.channel["item"].length() > 0)
{
var dateString:String = rssFeedXMLData.channel["item"][currentFeedIndex].pubDate;
var date:Date = new Date(Date.parse(dateString.replace(" Z","")));
if (date.toString() != "Invalid Date")
{
dateString = " @ " + FormatDate(date) + " " + FormatTime(date);
}
else
{
dateString = " @ " + dateString;
}
ins_rssTitle.text = rssFeedXMLData.channel.title + dateString;
ins_rssContent.text = " "
+ cleanDescription(rssFeedXMLData.channel["item"][currentFeedIndex].title) + " - "
+ cleanDescription(rssFeedXMLData.channel["item"][currentFeedIndex].description);
gettingNewFeed = false;
}
else
{
ins_rssContent.text = "";
gettingNewFeed = false;
}
}
// removes the things from the RSS content that I don't want.
function cleanDescription(p_string:String):String
{
if (p_string == null)
{
return '';
}
var str:String = p_string.replace(/<\/?[^>]+>/igm, ''); //remove html tags.
str = str.split("\r").join(". "); //replace line breaks with '. '
str = str.replace("\t"," "); //replace tabs with a single space.
str = str.replace(/(?:\.\s){2,}/g,". "); //replace multiple '. ' with a single one.
str = str.replace(/((https?|ftp|gopher|telnet|file|notes|ms-help):
((\/\/)|(\\\\))+[\w\d:#@%\/;$()~_?\+-=\\\.&]*)/igm, ' '); //replaces URL text with a single space
str = str.replace(/#[\w]{3,}/igm,' ') //replaces hash tags with a single space
str = str.replace(/\s{2,}/igm," "); //replace multiple spaces with a single space
return str;
}
function ioRSSListXMLLoaderErrorHandler(e:Event):void
{
trace("ioRSSListXMLLoaderErrorHandler:");
trace(e.toString());
}
// the idea below is that it sets the text to "" and sets gettingNewFeed to false, which should get the
// rssTickerTMR:Timer to try to get a band new feed. Theoretically, it should try and fail over and again
// until the network is once again accessible. This doesn't work at all.
function ioRSSFeedXMLLoaderErrorHandler(e:Event):void
{
trace("ioRSSFeedXMLLoaderErrorHandler:");
trace(e.toString());
ins_rssContent.text = "";
gettingNewFeed = false;
}
Does anyone know of a better way to approach this? I would appreciate any help that you all might be able to offer. Thanks!
EDIT!!!
As suggested by Will, I attempted to create a timer based network monitoring subsystem. In the IO_ERROR handler on my RSS Ticker, I stop the RSS timer, and start the Network Monitoring Timer. Every 10 seconds, it attempts to download a file from the server. It continues doing so until it works, at which point it turns its own timer off, the restarts the RSS timer.
Should work in theory. Not only that, but it does work if I change it to downloading a website instead of a network file. When using the network file, once it fails, it keeps failing, even after the connection is reestablished. Here is my code:
...
function ioRSSFeedXMLLoaderErrorHandler(e:Event):void
{
rssTickerTMR.stop();
networkMonitorTMR.start();
trace("ioRSSFeedXMLLoaderErrorHandler:");
trace(e.toString());
ins_rssTitle.text = "Waiting for connection...";
ins_rssContent.text = "";
}
// netowrk monitor
var networkMonitorXMLLoader:URLLoader = new URLLoader();
networkMonitorXMLLoader.addEventListener(Event.COMPLETE, networkMonitorXMLLLoaded);
networkMonitorXMLLoader.addEventListener(IOErrorEvent.IO_ERROR, networkMonitorXMLLoaderErrorHandler);
var networkMonitorTMR:Timer = new Timer(10000,0);
networkMonitorTMR.addEventListener(TimerEvent.TIMER, checkNetwork);
function checkNetwork(e:Event = null):void
{
networkMonitorXMLLoader.load(new URLRequest("//server/share/file.xml"));
}
function networkMonitorXMLLoaderErrorHandler(e:Event = null) :void
{
trace("Still Off");
}
function networkMonitorXMLLLoaded(e:Event = null) :void
{
trace("Back On");
rssTickerTMR.start();
networkMonitorTMR.stop();
}
Like I said, if i switch "//server/shar/file.xml" to http://www.google.ca, it works. When i unplug my ethernet, the network monitor starts, when I plug it back it, it switches back to the RSS... but with my network resource, it just continues to fail...