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");
}
}