功能简介

bgapi主要功能如下:

  1. 异步执行api命令, 异步, 从实现上面来说跟线程有关.
  2. 在刚调用的时候, 立即返回backgroup-uuid
  3. 在命令真正执行结束后, 会抛出一个事件, 事件中包含真正的返回结果.

具体如何实现, 需要参考代码.

代码文件

文件: mod_commands.c
函数: SWITCH_STANDARD_API(bgapi_function)

封装命令执行信息

因为需要异步执行, 所以必然有一个数据结构来封装待执行的命令信息, 传递给异步执行的线程.
此处的数据结构是:

  1. struct bg_job {
  2. char *cmd;
  3. char *arg;
  4. char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
  5. switch_memory_pool_t *pool;
  6. };

结构很简单, 包括命令、命令参数、后台任务uuid、线程池。

基本逻辑

  1. SWITCH_STANDARD_API(bgapi_function)
  2. {
  3. struct bg_job *job;
  4. switch_uuid_t uuid;
  5. switch_memory_pool_t *pool;
  6. switch_thread_t *thread;
  7. switch_threadattr_t *thd_attr = NULL;
  8. if (!cmd) {
  9. stream->write_function(stream, "-ERR Invalid syntax\n");
  10. return SWITCH_STATUS_SUCCESS;
  11. }
  12. //申请线程池,存储bg_job, 便于传递给后面的异步线程
  13. switch_core_new_memory_pool(&pool);
  14. job = switch_core_alloc(pool, sizeof(*job));
  15. //将命令拷贝到新pool里面
  16. job->cmd = switch_core_strdup(pool, cmd);
  17. job->pool = pool;
  18. //创建uuid, 用于跟踪这个后台执行的任务
  19. //调用者先收到这个任务uuid, 后续根据这个uuid,来过滤事件,获取真正的执行结果
  20. switch_uuid_get(&uuid);
  21. switch_uuid_format(job->uuid_str, &uuid);
  22. //创建线程,用于异步执行任务
  23. switch_threadattr_create(&thd_attr, job->pool);
  24. switch_threadattr_detach_set(thd_attr, 1);
  25. switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
  26. stream->write_function(stream, "+OK Job-UUID: %s\n", job->uuid_str);
  27. //线程中异步执行的函数是bgapi_exec
  28. switch_thread_create(&thread, thd_attr, bgapi_exec, job, job->pool);
  29. return SWITCH_STATUS_SUCCESS;
  30. }

上面代码的主要逻辑如下:

  1. 申请内存池, 用于保存异步任务信息
  2. 创建uuid,标识异步任务,并返回该uuid给调用者
  3. 创建线程,将异步任务和执行异步任务的函数传递过去

异步执行的逻辑也很简单:

  1. 使用下面的函数执行命令:

    1. if ((status = switch_api_execute(job->cmd, arg, NULL, &stream)) == SWITCH_STATUS_SUCCESS) {
    2. reply = stream.data;
    3. } else {
    4. freply = switch_mprintf("%s: Command not found!\n", job->cmd);
    5. reply = freply;
    6. }
  2. 通过BACKGROUND_JOB事件返回命令执行结果:

    1. if (switch_event_create(&event, SWITCH_EVENT_BACKGROUND_JOB) == SWITCH_STATUS_SUCCESS) {
    2. switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", job->uuid_str);
    3. switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command", job->cmd);
    4. if (arg) {
    5. switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command-Arg", arg);
    6. }
    7. switch_event_add_body(event, "%s", reply);
    8. switch_event_fire(&event);
    9. }