Discord library in plain C
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rest.c 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. //
  2. // Created by Memer on 24.08.18.
  3. // Copyright (c) 2018 Alexander Memer. All rights reserved.
  4. //
  5. #include <discord.h>
  6. #include <requests.h>
  7. #include <jansson.h>
  8. #include <log.h>
  9. void _ld_set_last_rest_error(struct ld_context *ctx, req_t *req)
  10. {
  11. log_warn("_ld_set_last_rest_error triggered");
  12. ctx->last_rest_status = malloc(sizeof(struct ld_rest_error));
  13. ctx->last_rest_status->what = (int)req->code;
  14. json_error_t err;
  15. json_t *res = json_loads(req->text, 0, &err);
  16. if (!res)
  17. {
  18. log_error("failed to parse json at line %d: %s", err.line, err.text);
  19. ctx->last_rest_status->text = "";
  20. json_decref(res);
  21. return;
  22. }
  23. json_t *message = json_object_get(res, "message");
  24. if (!json_is_string(message))
  25. {
  26. log_error("message is not a string");
  27. ctx->last_rest_status->text = "";
  28. json_decref(res);
  29. return;
  30. }
  31. char *_message = (char*)json_string_value(message);
  32. ctx->last_rest_status->text = malloc(strlen(_message) + 1);
  33. strcpy(ctx->last_rest_status->text, _message);
  34. }
  35. json_t *ld_get_request(struct ld_context *ctx, char *url)
  36. {
  37. req_t req;
  38. ctx->curl_handle = requests_init(&req);
  39. char *target = malloc(strlen(LD_API_ENDPOINT) + strlen(url) + 1);
  40. char *auth = malloc(strlen("Authorization: Bot ") + strlen(ctx->bot_token) + 1);
  41. sprintf(target, "%s%s", LD_API_ENDPOINT, url);
  42. sprintf(auth, "%s%s", "Authorization: Bot ", ctx->bot_token);
  43. requests_get_headers(ctx->curl_handle, &req, target, &auth, 1);
  44. free(target);
  45. free(auth);
  46. if(!req.ok)
  47. {
  48. _ld_set_last_rest_error(ctx, &req);
  49. return NULL;
  50. }
  51. json_t *res;
  52. json_error_t err;
  53. res = json_loads(req.text, 0, &err);
  54. requests_close(&req);
  55. if (!res)
  56. {
  57. log_error("failed to parse json on line %d: %s", err.line, err.text);
  58. return NULL;
  59. }
  60. return res;
  61. }
  62. json_t *ld_post_request(struct ld_context *ctx, char *url, json_t *contents)
  63. {
  64. req_t req;
  65. ctx->curl_handle = requests_init(&req);
  66. char *target = malloc(strlen(LD_API_ENDPOINT) + strlen(url) + 1);
  67. char *auth = malloc(strlen("Authorization: Bot ") + strlen(ctx->bot_token) + 1);
  68. sprintf(target, "%s%s", LD_API_ENDPOINT, url);
  69. sprintf(auth, "%s%s", "Authorization: Bot ", ctx->bot_token);
  70. if (!contents)
  71. {
  72. requests_post_headers(ctx->curl_handle, &req, target, "", &auth, 1);
  73. }
  74. else
  75. {
  76. requests_post_headers(ctx->curl_handle, &req, target, json_dumps(contents, 0), &auth, 1);
  77. }
  78. free(target);
  79. free(auth);
  80. if(!req.ok)
  81. {
  82. _ld_set_last_rest_error(ctx, &req);
  83. return NULL;
  84. }
  85. json_t *res;
  86. json_error_t err;
  87. res = json_loads(req.text, 0, &err);
  88. requests_close(&req);
  89. if (!res)
  90. {
  91. log_error("failed to parse json on line %d: %s", err.line, err.text);
  92. return NULL;
  93. }
  94. return res;
  95. }
  96. char *ld_get_gateway(struct ld_context *ctx)
  97. {
  98. json_t *res = ld_get_request(ctx, "/gateway");
  99. if (!res)
  100. {
  101. log_error("failed to get gateway url");
  102. return NULL;
  103. }
  104. json_t *gateway = json_object_get(res, "url");
  105. if (!json_is_string(gateway))
  106. {
  107. log_error("failed to parse url of gateway");
  108. json_decref(res);
  109. return NULL;
  110. }
  111. char *url = strdup(json_string_value(gateway));
  112. json_decref(gateway);
  113. json_decref(res);
  114. return url;
  115. }
  116. struct ld_gateway_bot_resp *ld_get_gateway_bot(struct ld_context *ctx)
  117. {
  118. json_t *res = ld_get_request(ctx, "/gateway/bot");
  119. if (!res)
  120. {
  121. log_error("failed to get gateway url");
  122. return NULL;
  123. }
  124. struct ld_gateway_bot_resp *r;
  125. r = malloc(sizeof(struct ld_gateway_bot_resp));
  126. json_t *gateway = json_object_get(res, "url");
  127. if (!json_is_string(gateway))
  128. {
  129. log_error("failed to parse json");
  130. json_decref(res);
  131. return NULL;
  132. }
  133. json_t *shards = json_object_get(res, "shards");
  134. if (!json_is_integer(shards))
  135. {
  136. log_error("failed to parse shards (not integer?)");
  137. json_decref(res);
  138. return NULL;
  139. }
  140. r->url = strdup(json_string_value(gateway));
  141. r->shards = (int)json_integer_value(shards);
  142. json_decref(gateway);
  143. json_decref(shards);
  144. json_decref(res);
  145. return r;
  146. }
  147. int ld_create_message(struct ld_context *ctx, char *channel_id, char *content)
  148. {
  149. char *target = malloc(39);
  150. sprintf(target, "/channels/%s/messages", channel_id);
  151. json_t *contents = json_object();
  152. json_t *_content = json_string(content);
  153. json_object_set_new(contents, "content", _content);
  154. json_t *res = ld_post_request(ctx, target, contents);
  155. free(target);
  156. if (json_object_size(res) <= 0)
  157. {
  158. log_warn("probably failed to create message");
  159. return -1;
  160. }
  161. json_decref(res);
  162. return 0;
  163. }
  164. int ld_get_channel(struct ld_context *ctx, char *channel_id, guild_channel_t *channel)
  165. {
  166. char *target = malloc(28);
  167. sprintf(target, "/channels/%s", channel_id);
  168. json_t *res = ld_get_request(ctx, target);
  169. free(target);
  170. if (json_object_size(res) <= 0)
  171. {
  172. log_warn("probably failed to get channel");
  173. return -1;
  174. }
  175. log_trace("%s", json_dumps(res, 0));
  176. json_t *id = json_object_get(res, "id");
  177. channel->id = strdup(json_string_value(id));
  178. json_decref(id);
  179. json_t *type = json_object_get(res, "type");
  180. channel->type = (int)json_integer_value(type);
  181. json_decref(type);
  182. if (channel->type == GUILD_TEXT || channel->type == GUILD_CATEGORY)
  183. {
  184. json_t *guild_id = json_object_get(res, "guild_id");
  185. channel->guild_id = strdup(json_string_value(guild_id));
  186. json_decref(guild_id);
  187. // TODO: permission_overwrites
  188. json_t *name = json_object_get(res, "name");
  189. channel->name = strdup(json_string_value(name));
  190. json_decref(name);
  191. if (channel->type == GUILD_TEXT)
  192. {
  193. // Topic is nullable
  194. json_t *topic = json_object_get(res, "topic");
  195. if (json_is_string(topic)) {
  196. channel->topic = strdup(json_string_value(topic));
  197. }
  198. json_decref(topic);
  199. json_t *nsfw = json_object_get(res, "nsfw");
  200. channel->nsfw = json_boolean_value(nsfw);
  201. json_decref(nsfw);
  202. json_t *last_message_id = json_object_get(res, "last_message_id");
  203. if (last_message_id) {
  204. if (json_is_string(last_message_id)) {
  205. channel->last_message_id = strdup(json_string_value(last_message_id));
  206. }
  207. json_decref(last_message_id);
  208. }
  209. }
  210. json_t *parent_id = json_object_get(res, "parent_id");
  211. if (json_is_string(parent_id))
  212. {
  213. channel->parent_id = strdup(json_string_value(parent_id));
  214. }
  215. json_decref(parent_id);
  216. json_t *position = json_object_get(res, "position");
  217. channel->position = (int)json_integer_value(position);
  218. json_decref(position);
  219. }
  220. else if (channel->type == GUILD_VOICE)
  221. {
  222. json_t *bitrate = json_object_get(res, "bitrate");
  223. channel->bitrate = (int)json_integer_value(bitrate);
  224. json_decref(bitrate);
  225. json_t *user_limit = json_object_get(res, "user_limit");
  226. channel->user_limit = (int)json_integer_value(user_limit);
  227. json_decref(user_limit);
  228. }
  229. else if (channel->type == DM || channel->type == GROUP_DM)
  230. {
  231. // TODO: recipients
  232. json_t *icon = json_object_get(res, "icon");
  233. if (icon)
  234. {
  235. if (json_is_string(icon))
  236. {
  237. channel->icon = strdup(json_string_value(icon));
  238. }
  239. json_decref(icon);
  240. }
  241. json_t *owner_id = json_object_get(res, "owner_id");
  242. channel->owner_id = strdup(json_string_value(owner_id));
  243. json_decref(owner_id);
  244. json_t *application_id = json_object_get(res, "application_id");
  245. if (application_id)
  246. {
  247. channel->application_id = strdup(json_string_value(application_id));
  248. json_decref(application_id);
  249. }
  250. }
  251. return 0;
  252. }