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 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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. requests_close(req);
  17. if (!res)
  18. {
  19. log_error("failed to parse json at line %d: %s", err.line, err.text);
  20. ctx->last_rest_status->text = "";
  21. json_decref(res);
  22. return;
  23. }
  24. json_t *message = json_object_get(res, "message");
  25. if (!json_is_string(message))
  26. {
  27. log_error("message is not a string");
  28. ctx->last_rest_status->text = "";
  29. json_decref(res);
  30. return;
  31. }
  32. char *_message = (char*)json_string_value(message);
  33. ctx->last_rest_status->text = malloc(strlen(_message) + 1);
  34. strcpy(ctx->last_rest_status->text, _message);
  35. }
  36. json_t *ld_get_request(struct ld_context *ctx, char *url)
  37. {
  38. req_t req;
  39. ctx->curl_handle = requests_init(&req);
  40. char *target = malloc(strlen(LD_API_ENDPOINT) + strlen(url) + 1);
  41. char *auth = malloc(strlen("Authorization: Bot ") + strlen(ctx->bot_token) + 1);
  42. sprintf(target, "%s%s", LD_API_ENDPOINT, url);
  43. sprintf(auth, "%s%s", "Authorization: Bot ", ctx->bot_token);
  44. requests_get_headers(ctx->curl_handle, &req, target, &auth, 1);
  45. free(target);
  46. free(auth);
  47. if(!req.ok)
  48. {
  49. _ld_set_last_rest_error(ctx, &req);
  50. return NULL;
  51. }
  52. json_t *res;
  53. json_error_t err;
  54. res = json_loads(req.text, 0, &err);
  55. requests_close(&req);
  56. if (!res)
  57. {
  58. log_error("failed to parse json on line %d: %s", err.line, err.text);
  59. return NULL;
  60. }
  61. return res;
  62. }
  63. json_t *ld_post_request(struct ld_context *ctx, char *url, json_t *contents)
  64. {
  65. req_t req;
  66. ctx->curl_handle = requests_init(&req);
  67. char *target = malloc(strlen(LD_API_ENDPOINT) + strlen(url) + 1);
  68. char *auth = malloc(strlen("Authorization: Bot ") + strlen(ctx->bot_token) + 1);
  69. sprintf(target, "%s%s", LD_API_ENDPOINT, url);
  70. sprintf(auth, "%s%s", "Authorization: Bot ", ctx->bot_token);
  71. if (!contents)
  72. {
  73. requests_post_headers(ctx->curl_handle, &req, target, "", &auth, 1);
  74. }
  75. else
  76. {
  77. requests_post_headers(ctx->curl_handle, &req, target, json_dumps(contents, 0), &auth, 1);
  78. }
  79. free(target);
  80. free(auth);
  81. if(!req.ok)
  82. {
  83. _ld_set_last_rest_error(ctx, &req);
  84. return NULL;
  85. }
  86. json_t *res;
  87. json_error_t err;
  88. res = json_loads(req.text, 0, &err);
  89. requests_close(&req);
  90. if (!res)
  91. {
  92. log_error("failed to parse json on line %d: %s", err.line, err.text);
  93. return NULL;
  94. }
  95. return res;
  96. }
  97. json_t *ld_patch_request(struct ld_context *ctx, char *url, json_t *contents)
  98. {
  99. req_t req;
  100. ctx->curl_handle = requests_init(&req);
  101. char *target = malloc(strlen(LD_API_ENDPOINT) + strlen(url) + 1);
  102. char *auth = malloc(strlen("Authorization: Bot ") + strlen(ctx->bot_token) + 1);
  103. sprintf(target, "%s%s", LD_API_ENDPOINT, url);
  104. sprintf(auth, "%s%s", "Authorization: Bot ", ctx->bot_token);
  105. if (!contents)
  106. {
  107. requests_patch(ctx->curl_handle, &req, target, "", &auth, 1, 1);
  108. }
  109. else
  110. {
  111. requests_patch(ctx->curl_handle, &req, target, json_dumps(contents, 0), &auth, 1, 1);
  112. }
  113. free(target);
  114. free(auth);
  115. if(!req.ok)
  116. {
  117. _ld_set_last_rest_error(ctx, &req);
  118. return NULL;
  119. }
  120. json_t *res;
  121. json_error_t err;
  122. res = json_loads(req.text, 0, &err);
  123. requests_close(&req);
  124. if (!res)
  125. {
  126. log_error("failed to parse json on line %d: %s", err.line, err.text);
  127. return NULL;
  128. }
  129. return res;
  130. }
  131. json_t *ld_delete_request(struct ld_context *ctx, char *url, json_t *contents)
  132. {
  133. req_t req;
  134. ctx->curl_handle = requests_init(&req);
  135. char *target = malloc(strlen(LD_API_ENDPOINT) + strlen(url) + 1);
  136. char *auth = malloc(strlen("Authorization: Bot ") + strlen(ctx->bot_token) + 1);
  137. sprintf(target, "%s%s", LD_API_ENDPOINT, url);
  138. sprintf(auth, "%s%s", "Authorization: Bot ", ctx->bot_token);
  139. if (!contents)
  140. {
  141. requests_delete(ctx->curl_handle, &req, target, "", &auth, 1);
  142. }
  143. else
  144. {
  145. requests_delete(ctx->curl_handle, &req, target, json_dumps(contents, 0), &auth, 1);
  146. }
  147. free(target);
  148. free(auth);
  149. if(!req.ok)
  150. {
  151. _ld_set_last_rest_error(ctx, &req);
  152. return NULL;
  153. }
  154. json_t *res;
  155. json_error_t err;
  156. res = json_loads(req.text, 0, &err);
  157. requests_close(&req);
  158. if (!res)
  159. {
  160. log_error("failed to parse json on line %d: %s", err.line, err.text);
  161. return NULL;
  162. }
  163. return res;
  164. }
  165. char *ld_get_gateway(struct ld_context *ctx)
  166. {
  167. json_t *res = ld_get_request(ctx, "/gateway");
  168. if (!res)
  169. {
  170. log_error("failed to get gateway url");
  171. return NULL;
  172. }
  173. json_t *gateway = json_object_get(res, "url");
  174. if (!json_is_string(gateway))
  175. {
  176. log_error("failed to parse url of gateway");
  177. json_decref(res);
  178. return NULL;
  179. }
  180. char *url = strdup(json_string_value(gateway));
  181. json_decref(gateway);
  182. json_decref(res);
  183. return url;
  184. }
  185. struct ld_gateway_bot_resp *ld_get_gateway_bot(struct ld_context *ctx)
  186. {
  187. json_t *res = ld_get_request(ctx, "/gateway/bot");
  188. if (!res)
  189. {
  190. log_error("failed to get gateway url");
  191. return NULL;
  192. }
  193. struct ld_gateway_bot_resp *r;
  194. r = malloc(sizeof(struct ld_gateway_bot_resp));
  195. json_t *gateway = json_object_get(res, "url");
  196. if (!json_is_string(gateway))
  197. {
  198. log_error("failed to parse json");
  199. json_decref(res);
  200. return NULL;
  201. }
  202. json_t *shards = json_object_get(res, "shards");
  203. if (!json_is_integer(shards))
  204. {
  205. log_error("failed to parse shards (not integer?)");
  206. json_decref(res);
  207. return NULL;
  208. }
  209. r->url = strdup(json_string_value(gateway));
  210. r->shards = (int)json_integer_value(shards);
  211. json_decref(gateway);
  212. json_decref(shards);
  213. json_decref(res);
  214. return r;
  215. }
  216. int ld_create_message(struct ld_context *ctx, char *channel_id, char *content)
  217. {
  218. char *target = malloc(39);
  219. sprintf(target, "/channels/%s/messages", channel_id);
  220. json_t *contents = json_object();
  221. json_t *_content = json_string(content);
  222. json_object_set_new(contents, "content", _content);
  223. json_t *res = ld_post_request(ctx, target, contents);
  224. free(target);
  225. if (json_object_size(res) <= 0)
  226. {
  227. log_warn("probably failed to create message");
  228. return -1;
  229. }
  230. json_decref(res);
  231. return 0;
  232. }
  233. int ld_get_channel(struct ld_context *ctx, char *channel_id, guild_channel_t *channel)
  234. {
  235. char *target = malloc(28);
  236. sprintf(target, "/channels/%s", channel_id);
  237. json_t *res = ld_get_request(ctx, target);
  238. free(target);
  239. if (json_object_size(res) <= 0)
  240. {
  241. log_warn("probably failed to get channel");
  242. return -1;
  243. }
  244. ld_channel_obj_to_type(res, channel);
  245. return 0;
  246. }
  247. int ld_modify_channel(struct ld_context *ctx, char *channel_id, struct ld_modify_channel_obj *modify)
  248. {
  249. ld_modify_channel_result(ctx, channel_id, modify, NULL);
  250. }
  251. int ld_modify_channel_result(struct ld_context *ctx, char *channel_id, struct ld_modify_channel_obj *modify, guild_channel_t *result)
  252. {
  253. json_t *contents = json_object();
  254. if (modify->name)
  255. {
  256. json_object_set_new(contents, "name", json_string(modify->name));
  257. }
  258. if (modify->position != -1)
  259. {
  260. json_object_set_new(contents, "position", json_integer(modify->position));
  261. }
  262. if (modify->topic)
  263. {
  264. json_object_set_new(contents, "topic", json_string(modify->topic));
  265. }
  266. if (modify->parent_id)
  267. {
  268. json_object_set_new(contents, "parent_id", json_string(modify->parent_id));
  269. }
  270. if (modify->nsfw != -1)
  271. {
  272. json_object_set_new(contents, "nsfw", json_boolean(modify->nsfw));
  273. }
  274. if (modify->bitrate != -1)
  275. {
  276. json_object_set_new(contents, "bitrate", json_integer(modify->bitrate));
  277. }
  278. if (modify->user_limit != -1)
  279. {
  280. json_object_set_new(contents, "user_limit", json_integer(modify->user_limit));
  281. }
  282. if (modify->permission_overwrites && modify->overwrites_size > 0)
  283. {
  284. json_t *overwrites = json_array();
  285. for (int i = 0; i < modify->overwrites_size; i++)
  286. {
  287. json_t *overwrite = json_object();
  288. json_object_set_new(overwrite, "id", json_string(modify->permission_overwrites[i].id));
  289. json_object_set_new(overwrite, "type", json_string(modify->permission_overwrites[i].type));
  290. json_object_set_new(overwrite, "deny", json_integer(modify->permission_overwrites[i].deny));
  291. json_object_set_new(overwrite, "allow", json_integer(modify->permission_overwrites[i].allow));
  292. json_array_append_new(overwrites, overwrite);
  293. }
  294. json_object_set_new(contents, "permission_overwrites", overwrites);
  295. }
  296. char *target = malloc(strlen("/channels/") + strlen(channel_id));
  297. sprintf(target, "/channels/%s", channel_id);
  298. json_t *res = ld_patch_request(ctx, target, contents);
  299. free(target);
  300. free(contents);
  301. if (!res)
  302. {
  303. log_error("probably failed to modify channel");
  304. return -1;
  305. }
  306. if (!result)
  307. {
  308. json_decref(res);
  309. return 0;
  310. }
  311. ld_channel_obj_to_type(res, result);
  312. return 0;
  313. }
  314. int ld_delete_channel(struct ld_context *ctx, char *channel_id)
  315. {
  316. char *target = malloc(strlen("/channels/") + strlen(channel_id));
  317. sprintf(target, "/channels/%s", channel_id);
  318. json_t *res = ld_delete_request(ctx, target, NULL);
  319. if (!res)
  320. {
  321. log_error("probably failed to delete channel");
  322. return -1;
  323. }
  324. free(target);
  325. json_decref(res);
  326. return 0;
  327. }