showroom.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #include <util/curl/curl-helper.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <jansson.h>
  5. #include <util/dstr.h>
  6. #include <util/darray.h>
  7. #include "util/base.h"
  8. #include <obs-module.h>
  9. #include <util/platform.h>
  10. #include "showroom.h"
  11. #include <util/threading.h>
  12. struct showroom_ingest_info {
  13. char *access_key;
  14. uint64_t last_time;
  15. struct showroom_ingest ingest;
  16. };
  17. static DARRAY(struct showroom_ingest_info) cur_ingests = {0};
  18. struct showroom_ingest invalid_ingest = {"", ""};
  19. void free_showroom_data(void)
  20. {
  21. for (size_t i = 0; i < cur_ingests.num; i++) {
  22. struct showroom_ingest_info *info = &cur_ingests.array[i];
  23. bfree(info->access_key);
  24. bfree((void *)info->ingest.key);
  25. bfree((void *)info->ingest.url);
  26. }
  27. da_free(cur_ingests);
  28. }
  29. static size_t showroom_write_cb(void *data, size_t size, size_t nmemb,
  30. void *user_pointer)
  31. {
  32. struct dstr *json = user_pointer;
  33. size_t realsize = size * nmemb;
  34. dstr_ncat(json, data, realsize);
  35. return realsize;
  36. }
  37. static struct showroom_ingest_info *find_ingest(const char *access_key)
  38. {
  39. struct showroom_ingest_info *ret = NULL;
  40. for (size_t i = 0; i < cur_ingests.num; i++) {
  41. struct showroom_ingest_info *info = &cur_ingests.array[i];
  42. if (strcmp(info->access_key, access_key) == 0) {
  43. ret = info;
  44. break;
  45. }
  46. }
  47. return ret;
  48. }
  49. #ifndef SEC_TO_NSEC
  50. #define SEC_TO_NSEC 1000000000ULL
  51. #endif
  52. static struct showroom_ingest_info *get_ingest_from_json(char *str,
  53. const char *access_key)
  54. {
  55. json_error_t error;
  56. json_t *root;
  57. root = json_loads(str, JSON_REJECT_DUPLICATES, &error);
  58. if (!root) {
  59. return NULL;
  60. }
  61. const char *url_str =
  62. json_string_value(json_object_get(root, "streaming_url_rtmp"));
  63. const char *key_str =
  64. json_string_value(json_object_get(root, "streaming_key"));
  65. struct showroom_ingest_info *info = find_ingest(access_key);
  66. if (!info) {
  67. info = da_push_back_new(cur_ingests);
  68. info->access_key = bstrdup(access_key);
  69. }
  70. bfree((void *)info->ingest.url);
  71. bfree((void *)info->ingest.key);
  72. info->ingest.url = bstrdup(url_str);
  73. info->ingest.key = bstrdup(key_str);
  74. info->last_time = os_gettime_ns() / SEC_TO_NSEC;
  75. json_decref(root);
  76. return info;
  77. }
  78. struct showroom_ingest *showroom_get_ingest(const char *server,
  79. const char *access_key)
  80. {
  81. struct showroom_ingest_info *info = find_ingest(access_key);
  82. CURL *curl_handle;
  83. CURLcode res;
  84. struct dstr json = {0};
  85. struct dstr uri = {0};
  86. long response_code;
  87. if (info) {
  88. /* this function is called a bunch of times for the same data,
  89. * so in order to prevent multiple unnecessary queries in a
  90. * short period of time, return the same data for 10 seconds */
  91. uint64_t ts_sec = os_gettime_ns() / SEC_TO_NSEC;
  92. if (ts_sec - info->last_time < 10) {
  93. return &info->ingest;
  94. } else {
  95. info = NULL;
  96. }
  97. }
  98. curl_handle = curl_easy_init();
  99. dstr_copy(&uri, server);
  100. dstr_cat(&uri, access_key);
  101. curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
  102. curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
  103. curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
  104. curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 30L);
  105. curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, showroom_write_cb);
  106. curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&json);
  107. curl_obs_set_revoke_setting(curl_handle);
  108. res = curl_easy_perform(curl_handle);
  109. dstr_free(&uri);
  110. if (res != CURLE_OK) {
  111. blog(LOG_WARNING,
  112. "showroom_get_ingest: curl_easy_perform() failed: %s",
  113. curl_easy_strerror(res));
  114. goto cleanup;
  115. }
  116. curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
  117. if (response_code != 200) {
  118. blog(LOG_WARNING,
  119. "showroom_get_ingest: curl_easy_perform() returned "
  120. "code: %ld",
  121. response_code);
  122. goto cleanup;
  123. }
  124. if (json.len == 0) {
  125. blog(LOG_WARNING,
  126. "showroom_get_ingest: curl_easy_perform() returned "
  127. "empty response");
  128. goto cleanup;
  129. }
  130. info = get_ingest_from_json(json.array, access_key);
  131. cleanup:
  132. curl_easy_cleanup(curl_handle);
  133. dstr_free(&json);
  134. return info ? &info->ingest : &invalid_ingest;
  135. }