1 module discord.api.util;
2
3 import std.uri,
4 std.array,
5 std.format,
6 std.algorithm.iteration;
7 import vibe.http.client,
8 vibe.stream.operations;
9 import discord.types,
10 discord.util.errors;
11
12 /**
13 Represents an error from the Discord API.
14 */
15 class APIError : BaseError {
16 this(int code, string msg) {
17 super("[%s] %s", code, msg);
18 }
19 }
20
21 /**
22 URL constructor to build routes
23 */
24 struct U {
25 private {
26 string _bucket;
27 string[] paths;
28 string[string] params;
29 }
30
31 @property string value() {
32 string url = this.paths.join("/");
33
34 if (this.params.length) {
35 string[] parts;
36 foreach (ref key, ref value; this.params) {
37 parts ~= format("%s=%s", key, encodeComponent(value));
38 }
39 url ~= "?" ~ parts.join("&");
40 }
41 return "/" ~ url;
42 }
43 this(string url) {
44 this.paths ~= url;
45 }
46 this(string paramKey, string paramValue) {
47 this.params[paramKey] = paramValue;
48 }
49 string getBucket() {
50 return this._bucket;
51 }
52 U opCall(string url) {
53 this.paths ~= url;
54 return this;
55 }
56 U opCall(Snowflake s) {
57 this.paths ~= s.toString();
58 return this;
59 }
60 U opCall(string paramKey, string paramValue) {
61 this.params[paramKey] = paramValue;
62 return this;
63 }
64 U bucket(string bucket) {
65 this._bucket = bucket;
66 return this;
67 }
68 U param(string name, string value) {
69 this.params[name] = value;
70 return this;
71 }
72 }
73
74 /**
75 Represents an error response from Discord API.
76 */
77 class APIResponse {
78 private {
79 HTTPClientResponse res;
80 }
81 string content;
82 this(HTTPClientResponse res) {
83 this.res = res;
84 this.content = res.bodyReader.readAllUTF8();
85 this.res.disconnect();
86 }
87
88 APIResponse ok() {
89 if (100 < this.statusCode && this.statusCode < 400) {
90 return this;
91 }
92 throw new APIError(this.statusCode, this.content);
93 }
94
95 @property string contentType() {
96 return this.res.contentType;
97 }
98
99 @property int statusCode() {
100 return this.res.statusCode;
101 }
102
103 @property VibeJSON vibeJSON() {
104 return parseJsonString(this.content);
105 }
106
107 string header(string name, string def="") {
108 if (name in this.res.headers) {
109 return this.res.headers[name];
110 }
111 return def;
112 }
113 }