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

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