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.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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. json_t *ld_patch_request(struct ld_context *ctx, char *url, json_t *contents)
  97. {
  98. req_t req;
  99. ctx->curl_handle = requests_init(&req);
  100. char *target = malloc(strlen(LD_API_ENDPOINT) + strlen(url) + 1);
  101. char *auth = malloc(strlen("Authorization: Bot ") + strlen(ctx->bot_token) + 1);
  102. sprintf(target, "%s%s", LD_API_ENDPOINT, url);
  103. sprintf(auth, "%s%s", "Authorization: Bot ", ctx->bot_token);
  104. if (!contents)
  105. {
  106. requests_patch(ctx->curl_handle, &req, target, "", &auth, 1, 1);
  107. }
  108. else
  109. {
  110. requests_patch(ctx->curl_handle, &req, target, json_dumps(contents, 0), &auth, 1, 1);
  111. }
  112. free(target);
  113. free(auth);
  114. if(!req.ok)
  115. {
  116. _ld_set_last_rest_error(ctx, &req);
  117. return NULL;
  118. }
  119. json_t *res;
  120. json_error_t err;
  121. res = json_loads(req.text, 0, &err);
  122. requests_close(&req);
  123. if (!res)
  124. {
  125. log_error("failed to parse json on line %d: %s", err.line, err.text);
  126. return NULL;
  127. }
  128. return res;
  129. }
  130. char *ld_get_gateway(struct ld_context *ctx)
  131. {
  132. json_t *res = ld_get_request(ctx, "/gateway");
  133. if (!res)
  134. {
  135. log_error("failed to get gateway url");
  136. return NULL;
  137. }
  138. json_t *gateway = json_object_get(res, "url");
  139. if (!json_is_string(gateway))
  140. {
  141. log_error("failed to parse url of gateway");
  142. json_decref(res);
  143. return NULL;
  144. }
  145. char *url = strdup(json_string_value(gateway));
  146. json_decref(gateway);
  147. json_decref(res);
  148. return url;
  149. }
  150. struct ld_gateway_bot_resp *ld_get_gateway_bot(struct ld_context *ctx)
  151. {
  152. json_t *res = ld_get_request(ctx, "/gateway/bot");
  153. if (!res)
  154. {
  155. log_error("failed to get gateway url");
  156. return NULL;
  157. }
  158. struct ld_gateway_bot_resp *r;
  159. r = malloc(sizeof(struct ld_gateway_bot_resp));
  160. json_t *gateway = json_object_get(res, "url");
  161. if (!json_is_string(gateway))
  162. {
  163. log_error("failed to parse json");
  164. json_decref(res);
  165. return NULL;
  166. }
  167. json_t *shards = json_object_get(res, "shards");
  168. if (!json_is_integer(shards))
  169. {
  170. log_error("failed to parse shards (not integer?)");
  171. json_decref(res);
  172. return NULL;
  173. }
  174. r->url = strdup(json_string_value(gateway));
  175. r->shards = (int)json_integer_value(shards);
  176. json_decref(gateway);
  177. json_decref(shards);
  178. json_decref(res);
  179. return r;
  180. }
  181. int ld_create_message(struct ld_context *ctx, char *channel_id, char *content)
  182. {
  183. char *target = malloc(39);
  184. sprintf(target, "/channels/%s/messages", channel_id);
  185. json_t *contents = json_object();
  186. json_t *_content = json_string(content);
  187. json_object_set_new(contents, "content", _content);
  188. json_t *res = ld_post_request(ctx, target, contents);
  189. free(target);
  190. if (json_object_size(res) <= 0)
  191. {
  192. log_warn("probably failed to create message");
  193. return -1;
  194. }
  195. json_decref(res);
  196. return 0;
  197. }
  198. int ld_get_channel(struct ld_context *ctx, char *channel_id, guild_channel_t *channel)
  199. {
  200. char *target = malloc(28);
  201. sprintf(target, "/channels/%s", channel_id);
  202. json_t *res = ld_get_request(ctx, target);
  203. free(target);
  204. if (json_object_size(res) <= 0)
  205. {
  206. log_warn("probably failed to get channel");
  207. return -1;
  208. }
  209. ld_channel_obj_to_type(res, channel);
  210. return 0;
  211. }
  212. int ld_modify_channel(struct ld_context *ctx, char *channel_id, struct ld_modify_channel_obj *modify)
  213. {
  214. ld_modify_channel_result(ctx, channel_id, modify, NULL);
  215. }
  216. int ld_modify_channel_result(struct ld_context *ctx, char *channel_id, struct ld_modify_channel_obj *modify, guild_channel_t *result)
  217. {
  218. json_t *contents = json_object();
  219. if (modify->name)
  220. {
  221. json_object_set_new(contents, "name", json_string(modify->name));
  222. }
  223. if (modify->position != -1)
  224. {
  225. json_object_set_new(contents, "position", json_integer(modify->position));
  226. }
  227. if (modify->topic)
  228. {
  229. json_object_set_new(contents, "topic", json_string(modify->topic));
  230. }
  231. if (modify->parent_id)
  232. {
  233. json_object_set_new(contents, "parent_id", json_string(modify->parent_id));
  234. }
  235. if (modify->nsfw != -1)
  236. {
  237. json_object_set_new(contents, "nsfw", json_boolean(modify->nsfw));
  238. }
  239. if (modify->bitrate != -1)
  240. {
  241. json_object_set_new(contents, "bitrate", json_integer(modify->bitrate));
  242. }
  243. if (modify->user_limit != -1)
  244. {
  245. json_object_set_new(contents, "user_limit", json_integer(modify->user_limit));
  246. }
  247. if (modify->permission_overwrites && modify->overwrites_size > 0)
  248. {
  249. json_t *overwrites = json_array();
  250. for (int i = 0; i < modify->overwrites_size; i++)
  251. {
  252. json_t *overwrite = json_object();
  253. json_object_set_new(overwrite, "id", json_string(modify->permission_overwrites[i].id));
  254. json_object_set_new(overwrite, "type", json_string(modify->permission_overwrites[i].type));
  255. json_object_set_new(overwrite, "deny", json_integer(modify->permission_overwrites[i].deny));
  256. json_object_set_new(overwrite, "allow", json_integer(modify->permission_overwrites[i].allow));
  257. json_array_append_new(overwrites, overwrite);
  258. }
  259. json_object_set_new(contents, "permission_overwrites", overwrites);
  260. }
  261. char *target = malloc(strlen("/channels/") + strlen(channel_id));
  262. sprintf(target, "/channels/%s", channel_id);
  263. json_t *res = ld_patch_request(ctx, target, contents);
  264. free(target);
  265. free(contents);
  266. if (!res)
  267. {
  268. log_error("probably failed to modify channel");
  269. return -1;
  270. }
  271. if (!result)
  272. {
  273. json_decref(res);
  274. return 0;
  275. }
  276. ld_channel_obj_to_type(res, result);
  277. return 0;
  278. }