Basic Examples of how to use SH_NAME_ONFAILURE


Example 1:  Detecting when your network connections have been severed, or failed to connect.  Under SockHop, all connections are asynchronous.  Because of that, detecting a connection that failed to connect (perhaps because the target computer was not turned on?), or a connection that connected, but was later severed (perhaps because the target computer crashed?) are done the same way.  If you wish to be notified when a connection fails (or fails to be set up), you must let SockHop know that when you set up the connection, by giving it an SH_NAME_ONFAILURE BMessage to post when the connection fails.

    // For this example, will add one child named "Joe" to the root node.
    BMessage msg(SH_COMMAND_ADDCOMPONENTS);
    msg.AddString(SH_NAME_TO, "/");
    msg.AddFlat(SH_NAME_CHILDREN, &SHNodeSpec("Joe", "beos.sockhop.com"));
 
    // Since we want to know when the connection fails, we will specify a BMessage to be
    // sent back to us.
    BMessage onFailureMsg('dead');     // choose any 'what' value here that you will recognize later

    // Address the success message to ourself.  Remember that it will be posted
    // from the parent of the deceased node.
    onFailureMsg.AddString(SH_NAME_TO, "/..");
 
    // Finally, add the on-success BMessage to the original BMessage before sending it.
    msg.AddMessage(SH_NAME_ONFAILURE, &onFailureMsg);
    root->PostMessage(&msg);

[... meanwhile, in your target BLooper's MessageReceived() method...]

    void MyLooper :: MessageReceived(BMessage * msg)
    {
        if (msg->what == 'dead')
        {
            printf("Got a death message back!  Our connection must have broken!\n");

            // We can find out exactly who it was who died this way:
            SHNodeSpec whoWasIt;
            if (msg->FindFlat(SH_NAME_REGARDING, &whoWasIt) == B_NO_ERROR)
            {
               printf("The child who died or could not be connected to is:\n");
               whoWasIt.PrintToStream();
            }
        }
    }


Example 2:  Detecting when your add-on worker could not be instantiated or started on a remote node.  If you want a very robust program, it's good to know when things don't work out, right?  Here is how to be notified if something goes wrong in the add-on download/object instantiation process for an SHWorker subclass, TestWorker.  Things work the exact same way for SHSorter downloads, regular file caching, symlink creation, etc.

    // Okay, let's start a TestWorker object running on the node "/Joe"
    // ("/Joe" is assumed to already be set up and running in your node tree)
    BMessage msg(SH_COMMAND_ADDCOMPONENTS);
    msg.AddString(SH_NAME_TO, "/Joe");

    // Create a worker, capture his soul into a BMessage, and add him to our request BMessage.
    TestWorker worker;
    BMessage archive;
    worker.Archive(&archive);
    msg.AddMessage(SH_NAME_WORKERS, &archive);

    // Now create a self-addressed, stamped BMessage that will be posted by "/Joe"
    // if the add-worker operation fails.
    BMessage onFailure('Fail');
    onFailure.AddString(SH_NAME_TO, "/..");
    msg.AddMessage(SH_NAME_ONFAILURE, &onFailure);

    root->PostMessage(&msg);
 


Fancy Examples of SH_NAME_ONFAILURE


Example 3:  Here is the same thing as above, but instead of just one TestWorker, this example will instantiate 10 TestWorkers and a custom SHSorter, as well as cache some other files onto "/Joe".  We will be notified individually for each operation if that particular operation fails.

    // Okay, let's start a TestWorker object running on the node "/Joe"
    // ("/Joe" is assumed to already be set up and running in your node tree)
    BMessage msg(SH_COMMAND_ADDCOMPONENTS);
    msg.AddString(SH_NAME_TO, "/Joe");

    // Put 10 SHTestWorkers into the BMessage.
    for (int i=0; i<10; i++)
    {
        TestWorker worker;
        BMessage archive;
        worker.Archive(&archive);
        msg.AddMessage(SH_NAME_WORKERS, &archive);
    }

    // Also we'll add a new SHBitChordSorter onto Joe.
    SHBitChordSorter customSorter(0x01);
    BMessage archive;
    customSorter.Archive(&archive);
    msg.AddMessage(SH_NAME_SORTERS, &archive);

    // And last but not least, some other files.
    // These files must be located in the current directory of your main program.
    SHFileSpec otherFiles;
    if ((otherFiles.AddFlavor("file1.txt", SH_ARCH_ANY) == B_NO_ERROR)) &&
        (otherFiles.AddFlavor("rose.jpg", SH_ARCH_ANY) == B_NO_ERROR)) &&
        (otherFiles.AddFlavor("yell.wav", SH_ARCH_ANY) == B_NO_ERROR)))
    {
       msg.AddMessage(SH_NAME_FILES, &otherFiles);
    }
    else printf("Error, couldn't add the other files, at least one of them is missing!\n");
 
    // Now create a self-addressed, stamped BMessage that will be posted by "/Joe"
    // each time something fails.
    BMessage onFailure('Fail');
    onFailure.AddString(SH_NAME_TO, "/..");
    msg.AddMessage(SH_NAME_ONFAILURE, &onFailure);

    // And send the whole thing off to SockHop land
    root->PostMessage(&msg);

[... meanwhile, in your target BLooper's MessageReceived() method...]

    void MyLooper :: MessageReceived(BMessage * msg)
    {
        if (msg->what == 'Fail')
        {
            printf("Got a failure message back!  Something has gone wrong!\n");
            printf("The problem was with this object:\n");

            // We can find out exactly what failed this way:
            // Note that depending on what failed, the SH_NAME_REGARDING field
            // may contain an SHFileSpec (for file caching failures), an SHNodeSpec
            // (for child creation failures), or a string (for other failures).
            SHNodeSpec whoWasItNode; 
            SHFileSpec whoWasItFile;
            const char * whoWasItString;
            if (msg->FindFlat(SH_NAME_REGARDING, &whoWasItFile) == B_NO_ERROR)
            {
               whoWasItFile.PrintToStream();
            }
            else if (msg->FindFlat(SH_NAME_REGARDING, &whoWasItNode) == B_NO_ERROR)
            {
               whoWasItNode.PrintToStream();
            }
            else if (msg->FindString(SH_NAME_REGARDING, &whoWasItString) == B_NO_ERROR)
            {
               printf("Failure point was [%s]\n", whoWasItString);
            }
            else printf("Hmm, I don't know WHAT it was that failed!  (This shouldn't happen)\n");
        }
    }