🌐 한국어

    초기화와 종료 API#

    헤더 파일#

    OasisAPI.h

    OasisAppDelgate 인터페이스#

    Oasis 초기화 시 OasisAppDelgate 인터페이스를 정의하여 사용할 수 있습니다. Oasis 컴포넌트가 어떠한 사유로 재시작이나 종료를 해야 경우에 OasisAppDelgate 인터페이스의 콜백 함수를 호출합니다.

    Note

    Oasis 초기화에 반드시 필요한 인터페이스는 아닙니다. 이 인터페이스는 현재 DDS 게이트웨이 프로세스에서만 사용되고 있습니다. 따라서 DDS 게이트웨이 프로세스를 사용하지 않는 응용 프로그램은 Oasis 초기화 시 이 인터페이스가 필요하지 않습니다.

    OasisAppDelgate는 아래와 같이 정의되어 있습니다.

    
    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
    Oasis가 예약된 자원이나 네트워크 프로토콜의 심각한 오류 등으로 종료해야 하는 경우에 이 함수가 호출 됩니다. 응용 프로그램은 모든 자원을 해제하고 종료하거나, 문제 원인을 해결하고 종료없이 계속 동작할 수 있습니다.
    매개변수
    reason_code  종료 이유 코드입니다. 아래 trigger_exit API 함수 참고합니다.
    reason_arg  종류 이유에 따른 상세 데이터 값입니다.
    reason_string  종류 이유 코드에 대한 설명입니다.
    bool queryExit ( )
    OasisAPI.h
    응응 프로그램에게 종료를 해도 되는지 여부를 묻습니다. 만일 응용프로그램이 백그라운드나 서비스로 동작할 경우, false를 리턴하여 종료 요청을 무시할 수 있습니다.
    리턴값
    • true: 종료해도 좋습니다.
    • false: 종료하면 안 됩니다.

    함수#

    int32_t initialize ( key_value_map_t & parameters )
    OasisAPI.h
    Oasis를 초기화 합니다.
    매개변수
    parameters  초기화에 필요한 key-value map 입니다.
    리턴값
    • 0: 성공
    • -1: 실패

    oasis::initialize 함수의 매개변수로 전달할 수 있는 key-value map은 아래와 같습니다.

    기본값
    필수
    설명
    offs-qsize-max
    10240
     
    파일시스템 내부의 쓰기용 Q 최대 크기를 지정합니다. 실제 메모리를 할당하지는 않습니다. KBytes 단위입니다.
    offs-disable
    0
     
    파일시스템을 사용하지 않습니다. "1"인 경우, 녹화나 재생 등의 컴포넌트에서 파일 저장과 읽기를 할 수 없습니다. Oasis 파일 시스템을 사용하지 않더라도 미디어 파일 읽기와 쓰기가 필요한 경우, "1"로 설정합니다.
    offs-overwrite-if-exist
    1
     
    같은 파일명의 파일이 있으면 덮어쓸지 여부를 지정합니다. 1값이면 덮어씁니다. 덮어쓰지 않을 경우, 이름을 변경하여 생성합니다.
    offs-cache-size
    0
     
    파일시스템 내부의 읽기용 캐쉬 크기를 지정합니다. 메모리를 할당합니다. KBytes 단위입니다. 0 값이면 사용하지 않습니다.
    offs-log-flags
    0
     
    파일시스템 내부 로그를 활성화합니다.
    media-cache-size
    4096
     
    녹화용 미디어 데이터 임시 저장 캐쉬 크기를 지정합니다. 녹화 시 이벤트 발생 시점 이전 시간의 데이터 보관 용도입니다. 녹화 트랙 개수와 오디오 비디오 인코딩 비트레이트, 메타데이터 크기 등을 고려하여 충분한 공간이 필요합니다. Kbytes 단위입니다.
    oasis-log-flags
    0
     
    Oasis 컴포넌트 로그를 활성화합니다. OasisAPI.h에 정의된 OASIS_LOG_DEBUG(0x02)가 있습니다.
    system-font-path
     
    Oasis가 사용하는 폰트 파일 경로입니다. TrueType 폰트를 지원합니다.
    system-font-size
    10
     
    Oasis가 사용하는 폰트 기본 크기입니다. 포인트 단위입니다.

    offs-log-flags 는 아래와 같은 값을 OR'ing 합니다.

    #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
    

    예로 Oasis 파일시스템에 읽거나 쓰는 로그를 출력하려면, 아래와 같이 설정합니다.

    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
    OasisAppDelegate로 부터 유도된 사용자 정의 객체와 함께 Oasis를 초기화합니다. Oasis 컴포넌트가 어떠한 사유로 재시작이나 종료를 해야 할 경우 OasisAppDelegate로 콜백 함수를 호출합니다.
    매개변수
    parameters  초기화에 필요한 key-value map 입니다.
    app_delegate  OasisAppDelegate로 부터 유도된 사용자 정의 객체입니다.
    리턴값
    • 0: 성공
    • -1: 실패
    int32_t finalize ( )
    Oasis를 해제합니다.
    리턴값
    • 0: 성공
    • -1: 실패
    void trigger_exit ( int32_t reason_code , const void * reason_arg , const char * reason_string )
    OasisAPI.h
    응용 프로그램이 Oasis 초기화 시에 OasisAppDelgate로 유도된 사용자 정의 객체를 인수로 전달할 경우, OasisAppDelgate::triggerExit 콜백 함수를 호출합니다. 응용 프로그램은 이 콜백함수에서 프로그램 종료 조치를 취할 수 있습니다. 만일 OasisAppDelgate로 유도된 사용자 정의 객체 없이 Oasis를 초기화한 경우, 이 함수는 아무 동작없이 바로 리턴됩니다.
    매개변수
    reason_code  종료 이유 코드입니다.
    reason_arg  종료 이유 코드에 따른 상세 데이터입니다. nullptr 일 수 있습니다.
    reason_string  종료 이유 코드에 따른 상세 설명입니다. nullptr 일 수 있습니다.

    종료 이유 코드는 아래와 같습니다.

    enum {
        kTriggerExitReasonCodeQuit = 0,
        kTriggerExitReasonCodeRestart = 1,
        kTriggerExitReasonCodeUpdated = 2,
        kTriggerExitReasonCodeOutOfResource = 3,
    };
    

    Note

    kTriggerExitReasonCodeOutOfResource 상황이 발생할 경우, 예를들어, 네트워크 버퍼를 할당할 수 없거나, 포트를 더 이상 할당할 수 없을 경우 등이 발생하면, query_exit 호출없이, 바로 trigger_exit를 호출할 수 있습니다. 실제 프로그램 종료는 응용 프로그램의 역할이기 때문에, 응용 프로그램은 실제 프로그램 종료없이, 자원 고갈 문제 원인을 해결할 수도 있습니다.

    bool query_exit ( )
    OasisAPI.h
    응용 프로그램이 Oasis 초기화 시에 OasisAppDelgate로 유도된 사용자 정의 객체를 인수로 전달할 경우, OasisAppDelgate::queryExit 콜백 함수를 호출합니다. 응용 프로그램은 이 콜백함수에서 프로그램의 종료 여부를 체크할 수 있습니다. 만일 OasisAppDelgate로 유도된 사용자 정의 객체 없이 Oasis를 초기화한 경우, 이 함수는 아무 동작없이 바로 리턴됩니다.
    리턴값
    • true: 프로그램을 종료해도 좋습니다.
    • false: 프로그램 종료가 허용되지 않습니다.

    Caution

    trigger_exitquery_exit는 Oasis 컴포넌트 내부에서 사용됩니다. 응용 프로그램에서 MediaObserver나 HttpUpStreamDelegate 등 Oasis 인터페이스로 부터 유도된 사용자 정의 인터페이스의 콜백함수에서 이 함수들을 사용할 필요는 없습니다.

    예제#

    #include "OasisAPI.h"
    #include "OasisLog.h"
    
    // oasis 네임스페이스를 명시하지 않으려면, 아래 줄의 코멘트를 제거합니다.
    // 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;
        }
    
        /*
            여기에 Oasis 컴포넌트를 추가로 초기화하고 사용합니다.
        */
    
    
        oasis::finalize();
    
    
        return 0;
    }
    

    OasisAppDelegate 사용예#

    아래 예는 웹 클라이언트가

    • "/restart" URL에 접속하면 kTriggerExitReasonCodeRestart 코드로 응응 프로그램을 종료하고,

      if(query_exit()) {
        trigger_exit(kTriggerExitReasonCodeRestart, nullptr, nullptr);
      }
      
    • "/upload" URL 에 접속하여 파일을 업로드 할 경우, kTriggerExitReasonCodeUpdated 코드로 응응 프로그램을 종료합니다.

      if(query_exit()) {
        trigger_exit(kTriggerExitReasonCodeUpdated, nullptr, "file updated");
      }
      

    응응 프로그램 종료 시 종료 코드에 따라서 응용 프로그램 동작을 모니터링하는 관리 프로세스에서 그에 상응하는 조치를 취할 수 있습니다. 예를 들어, 아래 예에서 종료코드가 "2" 일 경우, 관리 프로세스는 사용자가 전송한 파일을 이용하여 업데이트를 하고, 응용 프로그램을 재시작할 수 있습니다.

    Note

    이 예는 OasisAppDelegate 사용 예를 보여주는 것으로 실제 응용 프로그램단에서 재시작이나 업데이트 용도로 OasisAppDelegate 정의하여 사용할 필요는 없습니다. 재시작이나 업데이트 등은 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;
    }
    

    아래는 실행 로그 예입니다.

    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