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 }