🌐 English

    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();
    };
    
    void triggerExit ( int32_t reason_code , const void * reason_arg , const char * reason_string )
    OasisAPI.h
    This function is called when Oasis needs to terminate due to critical errors in reserved resources or network protocols, etc. The application can release all resources and terminate, or resolve the cause of the problem and continue operating without terminating.
    Parameters
    reason_code  The termination reason code. Refer to the trigger_exit API function below.
    reason_arg  Detailed data values based on the termination reason.
    reason_string  Description of the termination reason code.
    bool queryExit ( )
    OasisAPI.h
    Asks the application whether it is allowed to terminate. If the application is running as a background task or service, it can ignore the termination request by returning false.
    Return Value
    • true: Termination is allowed.
    • false: Termination is not allowed.

    Functions#

    int32_t initialize ( key_value_map_t & parameters )
    OasisAPI.h
    Initializes Oasis.
    Parameters
    parameters  The key-value map required for initialization.
    Return Value
    • 0: Success
    • -1: Failure

    The key-value map that can be passed as a parameter to the oasis::initialize function is as follows:

    Key
    Default
    M
    Description
    offs-qsize-max
    10240
     
    Specifies the maximum size of the internal write queue of the file system. It does not allocate actual physical memory. Measured in KBytes.
    offs-disable
    0
     
    Disables the use of the file system. If "1", components such as recording or playback cannot save and read files. If media file reading and writing are required even without using the Oasis file system, set this to "1".
    offs-overwrite-if-exist
    1
     
    Specifies whether to overwrite a file if a file with the same name exists. Overwrites if the value is 1. If it is not overwritten, it is created with a modified name.
    offs-cache-size
    0
     
    Specifies the internal read cache size of the file system. It allocates memory. Measured in KBytes. If the value is 0, it is not used.
    offs-log-flags
    0
     
    Enables the internal log of the file system.
    media-cache-size
    4096
     
    Specifies the temporary media data cache size for recording. This is used for keeping data prior to the point of event occurrence during recording. Sufficient space is required considering the number of recording tracks, audio/video encoding bitrates, metadata size, etc. Measured in KBytes.
    oasis-log-flags
    0
     
    Enables the Oasis component log. OASIS_LOG_DEBUG(0x02) is defined in OasisAPI.h.
    system-font-path
     
    The path to the font file used by Oasis. Supports TrueType fonts.
    system-font-size
    10
     
    The default font size used by Oasis. Measured in points.

    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);
    
    int32_t initialize ( key_value_map_t & parameters , const std::shared_ptr<OasisAppDelegate> & app_delegate )
    OasisAPI.h
    Initializes Oasis along with a user-defined object derived from OasisAppDelegate. If an Oasis component needs to be restarted or terminated for any reason, it calls the callback function through OasisAppDelegate.
    Parameters
    parameters  The key-value map required for initialization.
    app_delegate  The user-defined object derived from OasisAppDelegate.
    Return Value
    • 0: Success
    • -1: Failure
    int32_t finalize ( )
    Releases Oasis.
    Return Value
    • 0: Success
    • -1: Failure
    void trigger_exit ( int32_t reason_code , const void * reason_arg , const char * reason_string )
    OasisAPI.h
    If the application passes a user-defined object derived from 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.
    Parameters
    reason_code  The termination reason code.
    reason_arg  Detailed data based on the termination reason code. Can be nullptr.
    reason_string  Detailed description based on the termination reason code. Can be nullptr.

    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.

    bool query_exit ( )
    OasisAPI.h
    If the application passes a user-defined object derived from 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.
    Return Value
    • 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