User:Antony Fairport/Scripts/Grid Status Notifier

From Second Life Wiki
Jump to navigation Jump to search

If there's one constant source of vague annoyance in Second Life (okay, there isn't one, there's many more than one) it's the inability of other residents to check with the resources provided when there's a problem. While Linden Lab might not always update the grid status as a priority, it generally alerts people to upcoming planned outages (as does do the rather useful calendar feeds they provide -- subscribe to it in your calendar software of choice and you'll never be surprised by a planning rolling restart again). So it's always a little annoying (but not surprising) to see people asking why some sim is missing, or why it's restarting, etc..., when the grid status clearly says what's going on.

Of course, sometimes, problems hit out of the blue, they aren't planned, and, again, that's where the grid status comes in. If you're running a sim, or a store, or an event (dance, hunt, etc...), knowing about these issues as soon as possible can be very handy. While I personally try and keep on top of things by subscribing to the RSS feed of the grid status I'm seldom paying attention to my feed reader when I'm in-world.

That needs an in-world solution. What follows is what I'm now using. I can't and won't claim this as an original idea, the code is based on code by Dermot Core/DigitaL Scribe, but that code didn't work quite how I wanted so I re-wrote it from scratch (as much for fun as anything) and made it work "just so". I'm sharing what I wrote in the same way.

Just rez a prim, drop this in, and you're good to go. When it first loads it'll IM you the current status. Any time the latest status changes (either because it's a new status, or because it's been modified) it'll IM you it. This check is done every 5mins. Also, if anyone touches the prim the script is in, the current status is spoken in local chat.

//////////////////////////////////////////////////////////////////////
// Grid status notifier, by Antony Fairport
//
// Inspired by a similar script by Dermot Core / DigitaL Scribe.
// The original script didn't quite work as I'd like, so I took the
// core idea and made it work as I do like.
//
// To use simply create a prim and drop this inside it. Every 5mins
// the grid status is checked and, if it changes, an IM is sent to you
// Also, if anyone touches the prim the latest status (no matter if
// it has changed or not) will be spoken in local.

//////////////////////////////////////////////////////////////////////
// Constants
string  STATUS_FEED = "http://status.secondlifegrid.net/feed/";
integer CHECK_EVERY = 300;

//////////////////////////////////////////////////////////////////////
// Globals.
key     g_kRequest;
integer g_bSpecialRequest;
string  g_sLastItem = "";

//////////////////////////////////////////////////////////////////////
// Refresh the grid status.
RefreshStatus( integer bSpecialRequest )
{
    // Was this a special request by someone close by?
    g_bSpecialRequest = bSpecialRequest;

    // Kick off the request.    
    g_kRequest = llHTTPRequest( STATUS_FEED, [], "" );
}

//////////////////////////////////////////////////////////////////////
// String search and replace.
// Via http://wiki.secondlife.com/wiki/Library_Combined_Library#str_replace
string StrReplace( string str, string search, string replace )
{
    return llDumpList2String( llParseStringKeepNulls( ( str = "" ) + str, [ search ], [] ), replace );
}

//////////////////////////////////////////////////////////////////////
// Find the first element in the given XML document.
string GetFirstElement( string sTag, string sData )
{
    integer iStart = llSubStringIndex( sData, "<" + sTag + ">" ) + llStringLength( sTag ) + 2;
    integer iEnd   = llSubStringIndex( sData, "</" + sTag + ">" ) - 1;
    
    if ( ( iStart != -1 ) && ( iEnd != -1 ) )
    {
        return llGetSubString( sData, iStart, iEnd );
    }
    else
    {
        return "";
    }
}

//////////////////////////////////////////////////////////////////////
// Find the first <item> in the given document.
string GetFirstItem( string sData )
{
    return GetFirstElement( "item", sData );
}

//////////////////////////////////////////////////////////////////////
// Find the first <title> in the given document.
string GetTitle( string sItem )
{
    return GetFirstElement( "title", sItem );
}

//////////////////////////////////////////////////////////////////////
// Find the first <time> in the given document.
string GetTime( string sItem )
{
    return GetFirstElement( "pubDate", sItem );
}

//////////////////////////////////////////////////////////////////////
// Find the first <link> in the given document.
string GetLink( string sItem )
{
    return GetFirstElement( "link", sItem );
}

//////////////////////////////////////////////////////////////////////
// Find the first <description> in the given document.
string GetDescription( string sItem )
{
    return GetFirstElement( "description", sItem );
}

//////////////////////////////////////////////////////////////////////
// Have a stab at removing any <![CDATA[[...]]> markers.
string CleanCDATA( string s )
{
    // Does it look like it's wrapped as CDATA?
    if ( ( llGetSubString( s, 0, 9 ) == "<![CDATA[[" ) && ( llGetSubString( s, -3, -1 ) == "]]>" ) )
    {
        // Yup, top and tail it.
        return llGetSubString( s, 9, -4 );
    }
    else
    {
        // No, just go with that we've got.
        return s;
    }
}

//////////////////////////////////////////////////////////////////////
// Some final cleanup hacks.
string CleanupHack( string s )
{
    // This list will probably grow. Consider this a nasty kludge to
    // remove some of the more common encodings and make them
    // readable.
    return StrReplace( s, "&#8217;", "'" );
}

//////////////////////////////////////////////////////////////////////
// Format the given grid status.
string FormatStatus( string sItem )
{
    return
        "Title: "        + GetTitle( sItem ) + "\n" + 
        "Time: "         + GetTime( sItem )  + "\n" + 
        "Link: "         + GetLink( sItem )  + "\n" + 
        "Description:\n" + CleanupHack( CleanCDATA( GetDescription( sItem ) ) );
}

//////////////////////////////////////////////////////////////////////
// Default state.
default
{
    //////////////////////////////////////////////////////////////////
    // Set things up on state entry.
    state_entry()
    {
        // Set up the timer.
        llSetTimerEvent( CHECK_EVERY );
        
        // Do an initial check.
        RefreshStatus( FALSE );
    }

    //////////////////////////////////////////////////////////////////
    // Recact to a timer event.
    timer()
    {
        // Refresh the status.
        RefreshStatus( FALSE );
    }
    
    //////////////////////////////////////////////////////////////////
    // Recact to a touch event.
    touch_start( integer total_number )
    {
        // Refresh the status.
        RefreshStatus( TRUE );
    }
    
    //////////////////////////////////////////////////////////////////
    // Handle a HTTP response.
    http_response( key request_id, integer status, list metadata, string body )
    {
        // If the response is ours...
        if ( request_id == g_kRequest )
        {
            // Pull out the first item in the feed.
            string sItem = GetFirstItem( body );

            // If we got something
            if ( sItem != "" )
            {
                // If this was a special request...
                if ( g_bSpecialRequest )
                {
                    // ...just say what we've got in local.
                    llSay( 0, "Current Grid Status:\n" + FormatStatus( sItem ) );
                }
                else
                {
                    // ...otherwise this is a timer check. In which case
                    // we check to see if the latest status is different from
                    // the last time we looked.
                    if ( sItem != g_sLastItem )
                    {
                        // It is. Remember it.
                        g_sLastItem = sItem;
                        
                        // And IM the owner it.
                        llInstantMessage( llGetOwner(), "New grid status message detected:\n\n" + FormatStatus( sItem ) );
                    }
                }
            }
            else
            {
                // Have a moan.
                llSay( 0, "Problem getting grid status information." );
            }
        }
    }
}