Setup and Cleanup API#
Header File#
OasisAPI.h
OasisAppDelegate Interface#
When initializing Oasis, the OasisAppDelegate interface can be defined and used. The callback functions of the OasisAppDelegate interface are called when an Oasis component needs to be restarted or terminated for any reason.
Note
This interface is not mandatory for Oasis initialization. This interface is currently used only in the DDS Gateway Process. Therefore, applications that do not use the DDS Gateway process do not require this interface when initializing Oasis.
OasisAppDelegate is defined as follows:
class OasisAppDelegate
{
public:
OasisAppDelegate();
virtual ~OasisAppDelegate();
virtual void triggerExit(int32_t reason_code, const void *reason_arg, const char *reason_string);
virtual bool queryExit();
};
trigger_exit API function below.
false.
- true: Termination is allowed.
- false: Termination is not allowed.
Functions#
- 0: Success
- -1: Failure
The key-value map that can be passed as a parameter to the oasis::initialize function is as follows:
OASIS_LOG_DEBUG(0x02) is defined in OasisAPI.h.offs-log-flags performs OR'ing of the following values:
#define OFFS_LOG_IO_WRITE_BEGIN 0x00000001
#define OFFS_LOG_IO_WRITE_END 0x00000002
#define OFFS_LOG_IO_READ_BEGIN 0x00000004
#define OFFS_LOG_IO_READ_END 0x00000008
#define OFFS_LOG_IO_VERBOSE 0x00000010
#define OFFS_LOG_IO_DEBUG 0x00000020
For example, to output logs for reading from or writing to the Oasis file system, configure as follows:
parameters["offs-log-flags"] = std::to_string(OFFS_LOG_IO_WRITE_BEGIN|OFFS_LOG_IO_WRITE_END|OFFS_LOG_IO_READ_BEGIN|OFFS_LOG_IO_READ_END);
- 0: Success
- -1: Failure
OasisAppDelegate as an argument during Oasis initialization, it calls the OasisAppDelegate::triggerExit callback function. The application can take actions to terminate the program in this callback function. If Oasis is initialized without a user-defined object derived from OasisAppDelegate, this function returns immediately without any operation.
The termination reason codes are as follows:
enum {
kTriggerExitReasonCodeQuit = 0,
kTriggerExitReasonCodeRestart = 1,
kTriggerExitReasonCodeUpdated = 2,
kTriggerExitReasonCodeOutOfResource = 3,
};
Note
When a kTriggerExitReasonCodeOutOfResource situation occurs (for example, when a network buffer cannot be allocated or ports can no longer be assigned), trigger_exit can be called directly without calling query_exit. Since actual program termination is the responsibility of the application, the application may resolve the cause of the resource exhaustion problem without actually terminating the program.
OasisAppDelegate as an argument during Oasis initialization, it calls the OasisAppDelegate::queryExit callback function. The application can check whether the program is allowed to terminate in this callback function. If Oasis is initialized without a user-defined object derived from OasisAppDelegate, this function returns immediately without any operation.
- true: The program may be terminated.
- false: Program termination is not allowed.
Caution
trigger_exit and query_exit are used internally within Oasis components. It is not necessary for the application to use these functions inside callback functions of user-defined interfaces derived from Oasis interfaces, such as MediaObserver or HttpUpStreamDelegate.
Example#
#include "OasisAPI.h"
#include "OasisLog.h"
// To avoid specifying the oasis namespace, uncomment the line below.
// using namespace oasis;
#define OFFS_QUEUE_SIZE_KBYTES (40*1024)
#define OFFS_CACHE_SIZE_KBYTES (1024)
#define MEDIA_CACHE_SIZE_KBYTES (40*1024)
int main(int argc, char *argv[])
{
int32_t err;
oasis::key_value_map_t parameters;
parameters["offs-qsize-max"] = std::to_string(OFFS_QUEUE_SIZE_KBYTES);
parameters["offs-overwrite-if-exist"] = "1";
parameters["offs-cache-size"] = std::to_string(OFFS_CACHE_SIZE_KBYTES);
parameters["media-cache-size"] = std::to_string(MEDIA_CACHE_SIZE_KBYTES);
parameters["oasis-log-flags"] = std::to_string(OASIS_LOG_DEBUG);
if(oasis::initialize(parameters) < 0) {
DLOG(DLOG_ERROR, "Oasis init failed\n");
return -1;
}
/*
Initialize and use additional Oasis components here.
*/
oasis::finalize();
return 0;
}
Usage Example of OasisAppDelegate#
In the example below, when a web client
-
Accesses the "/restart" URL, it terminates the application with the code
kTriggerExitReasonCodeRestart,if(query_exit()) { trigger_exit(kTriggerExitReasonCodeRestart, nullptr, nullptr); } -
Accesses the "/upload" URL to upload a file, it terminates the application with the code
kTriggerExitReasonCodeUpdated.if(query_exit()) { trigger_exit(kTriggerExitReasonCodeUpdated, nullptr, "file updated"); }
Upon application termination, the management process monitoring the application can take corresponding measures based on the exit code. For example, in the example below, if the exit code is "2", the management process can perform an update using the file transmitted by the user and restart the application.
Note
This example is intended to demonstrate the usage of OasisAppDelegate, and it is not necessary to define and use OasisAppDelegate for restart or update purposes in an actual application stage. Restarting or updating can be handled logically without OasisAppDelegate.
#include "OasisAPI.h"
#include "OasisWeb.h"
#include "OasisLog.h"
#include "OasisUtil.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <signal.h>
#include <thread>
#include <mutex>
#include <memory>
#include <condition_variable>
#define DLOG_THIS 0x00080000
#undef DLOG_FLAGS
#define DLOG_FLAGS (DLOG_FLAGS_DEFAULT|DLOG_THIS/**/)
#undef DLOG_TAG
#define DLOG_TAG "APP-DELEGATE"
using namespace oasis;
static bool continue_running = true;
static int32_t app_exit_code = 0; // 1: restart, 2: update
void cancel_handler(int signum)
{
continue_running = false;
}
class MyAppDelegate : public OasisAppDelegate
{
public:
MyAppDelegate(bool run_in_background);
virtual ~MyAppDelegate();
virtual void triggerExit(int32_t reason_code, const void *reason_arg, const char *reason_string);
virtual bool queryExit();
protected:
bool run_in_background_;
};
MyAppDelegate::MyAppDelegate(bool run_in_background)
: run_in_background_(run_in_background)
{
}
MyAppDelegate::~MyAppDelegate()
{
}
void MyAppDelegate::triggerExit(int32_t reason_code, const void *reason_arg, const char *reason_string)
{
if(reason_code == kTriggerExitReasonCodeRestart) {
app_exit_code = 1;
} else if(reason_code == kTriggerExitReasonCodeUpdated) {
app_exit_code = 2;
} else {
app_exit_code = -1;
}
continue_running = false;
}
bool MyAppDelegate::queryExit()
{
if(!run_in_background_) {
TRACE0("Can not exit because it runs in terminal.\n");
}
return run_in_background_;
}
class MyHttpUpStreamDelegate : public HttpUpStreamDelegate
{
public:
MyHttpUpStreamDelegate() { }
virtual ~MyHttpUpStreamDelegate() { }
public:
virtual void onRequest(const NetMessageRef &msg) {
std::string url;
netMessageUriGetPath(msg, url);
ASSERT(netMessageIsRequest(msg));
if(!netMessageIsRequest(msg)) {
return;
}
NetMessageRef res = netMessageCreate(msg, false);
if(res == nullptr) {
netMessageAbortConnection(msg);
return;
}
std::string method;
netMessageGetMethod(msg, method);
fprintf(stdout, "onRequest [%s]: %s\n", method.c_str(), url.c_str());
netMessageSetStatusCodeAndReasonString(res, 200, "OK");
netMessageSetHeaderField(res, "Connection", "close");
if(url == "/upload") {
//send the upload data form.
std::string upload_form = R"(
<form action="/update-now" method="POST" enctype="multipart/form-data">
<label for="file-upload">Select a file:</label>
<input type="file" id="file-upload" name="myFile">
<button type="submit">Upload</button>
</form>)";
netMessageSetContent(res, "text/html", upload_form.c_str(), upload_form.size());
netMessagePost(res);
} else if(url == "/update-now") {
std::string content_type, filename;
ssize_t size = netMessageGetFormDataFileData(msg, "myFile", content_type, filename, nullptr);
if(size <= 0) {
netMessageSetStatusCodeAndReasonString(res, 400, "Bad Request");
netMessagePost(res);
return;
}
fprintf(stdout, "myFile: %s, content type %s, size %zd\n", filename.c_str(), content_type.c_str(), size);
if(size > 0) {
//save to the data folder
char path[PATH_MAX];
sprintf(path, "/tmp/%s", filename.c_str());
ssize_t saved_size = netMessageSaveFormDataFileDataAs(msg, "myFile", path);
fprintf(stdout, "myFile: ==> saved to %s, size %zd\n", path, saved_size, size);
}
if(query_exit()) {
trigger_exit(kTriggerExitReasonCodeUpdated, nullptr, "file updated");
netMessagePost(res);
} else {
netMessageSetStatusCodeAndReasonString(res, 400, "Bad Request");
netMessagePost(res);
}
} else if(url == "/restart") {
if(query_exit()) {
trigger_exit(kTriggerExitReasonCodeRestart, nullptr, nullptr);
netMessagePost(res);
} else {
netMessageSetStatusCodeAndReasonString(res, 400, "Bad Request");
netMessagePost(res);
}
} else {
netMessageSetStatusCodeAndReasonString(res, 400, "Bad Request");
netMessagePost(res);
}
}
virtual void onResponse(const NetMessageRef &msg) {
}
};
void printUsage(const char *pgname)
{
fprintf(stderr, "USAGE: %s [-p <port number>]\n", pgname);
}
int main(int argc, char* argv[])
{
int32_t err;
int c;
int32_t http_port = 80;
std::shared_ptr<MyHttpUpStreamDelegate> http_delegate;
HttpServerRef http_server;
//assume this app is running in background so that the /restart request is granted.
std::shared_ptr<MyAppDelegate> app_delegate = std::make_shared<MyAppDelegate>(true);
opterr = 0;
while ((c = getopt(argc, argv, "p:h")) != -1) {
switch (c) {
case 'p':
if(optarg == nullptr) {
fprintf(stderr, "error: bad option argument '%c'\n", optopt);
return -1;
}
http_port = atoi(optarg);
if(http_port <= 0 || http_port > 65535) {
fprintf(stderr, "bad port number: %d\n", http_port);
return -1;
}
break;
case 'h':
default:
printUsage(argv[0]);
return -1;
}
}
key_value_map_t parameters;
parameters["offs-disable"] = "1";
if(oasis::initialize(parameters, app_delegate) < 0) {
fprintf(stderr, "Oasis init failed\n");
return -1;
}
parameters.clear();
parameters["port"] = std::to_string(http_port);
parameters["root-dir"] = "/tmp";
parameters["content-length-max"] = std::to_string(200*1024*1024);
parameters["cache-dir"] = "/tmp";
parameters["cached-content-types"] = "multipart/form-data,multipart/mixed";
http_delegate = std::make_shared<MyHttpUpStreamDelegate>();
http_server = oasis::createHttpServer(parameters, http_delegate);
if (http_server) {
err = oasis::startHttpServer(http_server);
ASSERT(err == 0);
if(err < 0) {
fprintf(stderr, "HTTPS server failed\n");
goto done;
}
fprintf(stdout, "HTTP running at %d...\n", http_port);
}
do {
usleep(100000);
} while(continue_running);
done:
if(http_server) {
oasis::destroyHttpServer(http_server);
}
oasis::finalize();
fprintf(stdout, "app exit code: %d\n", (uint8_t)(app_exit_code&0xff));
return app_exit_code;
}
Below is an example of the execution log:
OFFS disabled (virtual file size max.: 1024 MBytes)
HTTP running at 80...
onRequest [GET]: /upload
onRequest [GET]: /favicon.ico
onRequest [POST]: /update-now
myFile: oasis-fw-v101.zip, content type application/zip, size 4669286
myFile: ==> saved to /tmp/oasis-fw-v101.zip, size 4669286
app exit code: 2